LifePlay-Revival/Docs/Migration/etat/REL/MAPDL1/MAPDL1-E3B-VAL.md
2026-10-22 21:10:39 +02:00

294 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Fiche MAPDL1-E3B-VAL — Niveau N1 — Modèle prévu haiku | utilisé haiku (claude-haiku-5-5, déclaré par l'environnement ; non vérifié par `claude -p`) — Agent lp-validator — Skills lp-validate, sk-recount, sk-protocol, debug-verification
# MAPDL1-E3B-VAL : validation statique de l'étape E5, téléchargement et pose des packs (2026-10-22)
Hors gabarit : aucun. Gabarit VAL (`D:\Game\LifePlay-Sandbox\Tools\claude\skills\lp-doc\gabarits.md`) suivi, sections 1 à 6 dans l'ordre. La fiche demande en plus le tableau des critères (§ 5), les MD5 (§ 3), les sorties brutes (§ 3) et les fichiers à commiter (fin de document).
Lecture seule. Aucune compilation, aucun commandlet, aucun éditeur, aucun lancement du jeu, aucun appel réseau. `Tools\Build.ps1 -FromLog` non lancé : il écrit un résumé dans `etat\` (lot MAPDL1-E2T hors table de `Tools\EtatDir.ps1`, avertissement déjà noté dans `MAPDL1-E2T-BUILD.md` § 2) ; le recomptage des journaux est fait par Grep (§ 3.10). `LPTestStringCompat` non lancé (commandlet interdit par la fiche).
**Verdict global : PASS-STATIC.** Aucun critère de la fiche § 3 n'est contredit. Une réserve de code reste ouverte (R-1, § 5). Les points de jeu sont reportés (§ 2 et § 6).
Relevés : 2026-10-22, mtimes des fichiers E5 entre 16:49:22 et 17:27:49 ; journaux E2T écrits à 17:29:09 et 17:31:09.
## 1. Fiches amont relues
- `MAPDL1-E5-FICHE.md` : lue en entier (127 l.).
- `MAPDL1-E5-IMPL.md` : lue en entier (§ 1 à 6, Constats 1 à 3).
- `MAPDL1-E2T-BUILD.md` : lue en entier (compilation éditeur et jeu, correctif C2365).
- `MAPDL1-E3-VAL.md` : lue en entier (forme du livrable, sections 1 à 7).
- `MAPDL1-JOURNAL-BROUILLON.md` : lue en entier (ligne ERR du correctif `UI`).
- Instantanés lus : `D:\Game\LifePlay_Backup_5.5\MAPDL1-E5\manifest.csv`, `D:\Game\LifePlay_Backup_5.5\MAPDL1-E2T\manifest.csv` ; fichiers `…\MAPDL1-E5\Source\LifePlay\LPCityMapsSubsystem.h`, `LPCityMapsSubsystem.cpp`, `LifePlay.Build.cs`, `…\MAPDL1-E5\Content\Data\LPCityMaps.json` (diffs § 4) ; `…\MAPDL1-E2T\Source\LifePlay\LPCityMapsDownload.cpp` (diff § 3.11).
- Code lu en entier : `LPCityMapsDownload.h` (180 l.), `LPCityMapsDownload.cpp` (1406 l.), `LPCityMapsWindow.h` (67 l.), `LPCityMapsWindow.cpp` (585 l.), `LPCityMapsSubsystem.h` (178 l.), `LPCityMapsSubsystem.cpp` (946 l.), `LifePlay.Build.cs` (63 l.), `LPCityMaps.json` (15 l.).
- Non relus en entier : les deux licences (copies à l'octet, MD5 seulement) ; `MAPDL1-E1-IMPL.md` et `MAPDL1-E4-TESTS.md` (Grep seulement).
- Moteur 5.8 lu (fichier:ligne) : `D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\Core\Public\HAL\FileManager.h:110, 113` (signatures de `Copy` et `Move`) ; `…\Core\Private\HAL\FileManagerGeneric.cpp:136-147` (`Copy`), `:175-234` (`CopyWithProgress`, suppression l. 233), `:299-325` (`Move`, suppression de la destination l. 303 si `Replace`).
## 2. Points à confirmer des IMPL : un par ligne
Points de `MAPDL1-E5-IMPL.md` § 5 (V-1 à V-15) et écarts E-1 à E-6 (voir Constats).
| Point (E5-IMPL § 5) | Verdict | Preuve |
|---|---|---|
| V-1 includes THIRD_PARTY autour d'OpenSSL et libzip | PASS (compilation) | `LPCityMapsDownload.cpp:16-23` ; journaux E2T sans `error C` ni `error LNK` (§ 3.10) ; jeu lié `Result: Succeeded` (E2T-BUILD § 5). |
| V-2 push/pop macro de `commdlg.h` | PASS (compilation) | `LPCityMapsDownload.cpp:29-49` ; 0 `warning C` dans les deux journaux (§ 3.10). |
| V-3 `BindSP`, `FTickerDelegate::CreateSP`, `Async`, lambdas | PASS (compilation) | Journal jeu : `Result: Succeeded` (ligne 38), unités 1 à 9 compilées (E2T-BUILD § 2). |
| V-4 attributs `*_Lambda` Slate | PASS (compilation) | `LPCityMapsWindow.cpp:177-236`, `:300-304`, `:334-345`, `:396-409` ; journaux sans erreur. |
| V-5 0 avertissement nouveau | PASS | Grep `warning C` : 0 dans les deux journaux (§ 3.10). Avertissements UBT `Plugin 'HyperAIStudio'` connus (E2T-BUILD § 4). |
| V-6 liaison HTTP, OpenSSL, libzip, Development | PASS (liaison Development) | `LifePlay.exe` lié, `Result: Succeeded` (journal jeu, E2T-BUILD § 5). Liaison Shipping (`comdlg32`) : reporté (jeu, non compilé). |
| V-7 `Content/Data/Licenses/*.txt` dans le pak | reporté (cuisson) | `Config\DefaultGame.ini:75` présent (§ 3.6). Stage UFS récursif non lu ici. |
| V-8 rendu de la fenêtre | reporté (jeu) | `LPCityMapsWindow.cpp:245-258` (fond, fenêtre, boutons). |
| V-9 redirections, `Range`, `Content-Range` | reporté (jeu, réseau) | `LPCityMapsDownload.cpp:852-859` (`Range`), `:921-926` (URL finale), `:962` (`Content-Range`). Aucun réseau en VAL. |
| V-10 coupure, reprise, 200 sur reprise, SHA faux, miroir, recours | reporté (jeu) | `:942-952` (200 sur reprise), `:1158-1163` (SHA faux), `:1009-1031` (URL suivante puis recours). |
| V-11 pose transactionnelle, retour arrière, `_ancien`, « Restart required » | reporté (jeu empaqueté) ; lecture statique faite | `:523-597` (pose), `:313-325` (retour arrière), `LPCityMapsSubsystem.cpp:846-853` (RestartRequired). |
| V-12 éditeur : « Download only » possible, « Full install » refusé | reporté (jeu éditeur) ; statique établi | `LPCityMapsDownload.cpp:773-778`, `:1268-1273` ; `LPCityMapsWindow.cpp:457-465`. |
| V-13 `Deinitialize` pendant un téléchargement | reporté (jeu) ; statique établi | `LPCityMapsSubsystem.cpp:299-304` (fermeture) ; `LPCityMapsDownload.cpp:609-622` (annulation, `.part` gardé). |
| V-14 dépôt : ordre E1, E5, STM1 | PASS (statique) ; ordre de commit reporté au gardien | `git status` (§ 3.8) : E5 en `??`, `LifePlay.Build.cs` et `DefaultGame.ini` en ` M`. |
| V-15 reste d'E1 (E-1 ticker, V-5 à V-12 d'E1) | reporté (E1, jeu) ; diff de `DecorateRows` lu | Le diff E5 n'ajoute à `DecorateRows` que la branche `RestartRequired` (`LPCityMapsSubsystem.cpp:755-773`, § 4). |
## 3. Critères rejoués (commande → résultat)
### 3.1 MD5 (`Get-FileHash -Algorithm MD5`), comparés à `MAPDL1-E5-IMPL.md` § 1
```
C1070FF639EF5710578BA33FB32E51D4 …\Source\LifePlay\LPCityMapsDownload.h
8319FC65523AF62DEE70A41ED98217D0 …\Source\LifePlay\LPCityMapsDownload.cpp
E2F30E7FE5814C99E7816D42DF44FBDD …\Source\LifePlay\LPCityMapsWindow.h
094FF220C4827C11594338163085408E …\Source\LifePlay\LPCityMapsWindow.cpp
7B7222797ED66A664F157058D3268228 …\Source\LifePlay\LPCityMapsSubsystem.h
568B7217AC1B456096E6FE47A74839CB …\Source\LifePlay\LPCityMapsSubsystem.cpp
38C28745AC538EE3A643A016A125EA16 …\Source\LifePlay\LifePlay.Build.cs
00298B7B8846244BD4992D61A8C306BD …\Content\Data\LPCityMaps.json
B1DAB51315B0BA903B527ECD5A988666 …\Content\Data\Licenses\OpenStreetMap_Geodata_License.txt
FB4E3868914D1822BA2974106C0FBDFE …\Content\Data\Licenses\Vinfamy_License.txt
B1DAB51315B0BA903B527ECD5A988666 …\Licenses\OpenStreetMap_Geodata_License.txt
FB4E3868914D1822BA2974106C0FBDFE …\Licenses\Vinfamy_License.txt
```
Résultat : 11 fichiers identiques à IMPL § 1 (« après »), à la lettre. Seul écart : `LPCityMapsDownload.cpp`, MD5 `8319FC65…` au lieu de `0F5D9DDD…` (IMPL), écart attendu et permis par la fiche (correctif `UI`). Preuve que c'est le seul changement : § 3.11.
Fichiers STM1 (`Get-FileHash`, 9 fichiers) : `CC146CC6…` `LPCityWaterSubsystem.cpp`, `4A6C6711…` `.h`, `E5027FD7…` `LPCityWaterMask.h`, `F3783338…` `LPCityNamesSubsystem.cpp`, `10639483…` `.h`, `01CC49D8…` `LPCityHouses.h`, `B4FF95AE…` `LPCityLandmarks.h`, `7B44F5FA…` `LPAssetRegistryHelpers.cpp`, `8E3B725A…` `.h`. Résultat : 9/9 identiques à `MAPDL1-E5-IMPL.md` Constats 2 (valeurs complètes relues). Référence « avant » indépendante : absente (IMPL § 1 ne couvre pas STM1) ; dates d'écriture STM1 antérieures à l'instantané E5 (`MAPDL1-E3-VAL.md` § 3.3).
### 3.2 Fins de ligne : `Tools\FileCheck.ps1`
Commande : `pwsh -NoProfile -Command "& 'D:\Game\LifePlay-master 5.8\Tools\FileCheck.ps1' -Path @(…10 chemins…)"`
```
LF 0 180 0 - C1070FF639EF5710578BA33FB32E51D4 Source\LifePlay\LPCityMapsDownload.h
LF 0 1406 0 - 8319FC65523AF62DEE70A41ED98217D0 Source\LifePlay\LPCityMapsDownload.cpp
LF 0 67 0 - E2F30E7FE5814C99E7816D42DF44FBDD Source\LifePlay\LPCityMapsWindow.h
LF 0 585 0 - 094FF220C4827C11594338163085408E Source\LifePlay\LPCityMapsWindow.cpp
LF 0 178 0 - 7B7222797ED66A664F157058D3268228 Source\LifePlay\LPCityMapsSubsystem.h
LF 0 946 0 - 568B7217AC1B456096E6FE47A74839CB Source\LifePlay\LPCityMapsSubsystem.cpp
LF 0 63 0 - 38C28745AC538EE3A643A016A125EA16 Source\LifePlay\LifePlay.Build.cs
LF 0 15 0 - 00298B7B8846244BD4992D61A8C306BD Content\Data\LPCityMaps.json
LF 0 155 0 - B1DAB51315B0BA903B527ECD5A988666 Content\Data\Licenses\OpenStreetMap_Geodata_License.txt
LF 0 5 0 - FB4E3868914D1822BA2974106C0FBDFE Content\Data\Licenses\Vinfamy_License.txt
fichiers=10 LF=10 alertes=0 introuvables=0
```
Résultat : 0 alerte (critère de la fiche § 1 : 0 alerte attendue). Lignes CR = 0 et BOM = 0 sur les 10 fichiers. Code de sortie : l'outil Bash n'a pas rendu de code de sortie pour cette commande ; le résumé « alertes=0 » est la preuve retenue.
Note : `LPCityMapsDownload.cpp` = 1406 l. (IMPL : 1403) ; les 3 lignes d'écart sont celles du correctif (§ 3.11).
### 3.3 `Test-Json` de `LPCityMaps.json` et champs `fichier`
Commande : `Get-Content -Raw -LiteralPath '…\Content\Data\LPCityMaps.json' | Test-Json`, puis lecture des champs.
```
True
osm -> Data/Licenses/OpenStreetMap_Geodata_License.txt
lifeplay_ancienne -> Data/Licenses/Vinfamy_License.txt
```
Résultat : JSON valide. Les deux chemins pointent sur `Content\Data\Licenses\` (fichiers présents, § 3.1 et § 3.7).
### 3.4 Critère a : suppressions et `Move`
- Grep `Delete|DeleteDirectory|RemoveDirectory|DeleteFile|\.Delete\(` sur `Source\LifePlay\LPCityMaps*` : **aucun résultat**.
- Grep `Remove` (même périmètre, `LPCityMapsDownload.*`) : 4 occurrences, toutes `FTSTicker::GetCoreTicker().RemoveTicker(...)` (`LPCityMapsDownload.cpp:615, 1039, 1094, 1329`). Ce ne sont pas des suppressions de fichier.
- Grep `Copy\(|Move\(|Replace` : `Move` une seule fois, `LPCityMapsDownload.cpp:112` : `IFileManager::Get().Move(*Destination, *Source, false, false, false, true)`. Tous les appels passent par `MoveFileSafe` (`:110-113`), donc `Replace = false` (3e argument) partout. `Copy` : `LPCityMapsDownload.cpp:1235` : `FileManager.Copy(*Final, *SourcePath, false)`.
- Moteur : `FileManager.h:113` (`Move(Dest, Src, Replace=1, EvenIfReadOnly=0, Attributes=0, bDoNotRetryOrError=0)`) ; `FileManager.h:110` (`Copy(…, Replace=1, …)`). Le `Replace` vrai supprime la destination (`FileManagerGeneric.cpp:303`) : évité ici.
Résultat : **établi**. Réserve R-4 : la copie du moteur supprime sa propre destination partielle en cas d'échec (`FileManagerGeneric.cpp:231-234`) ; cette destination est neuve (la version précédente est mise de côté avant, `LPCityMapsDownload.cpp:1229-1233`), et la source (fichier du joueur) n'est jamais supprimée.
### 3.5 Critère 4 (compilation sans l'addon)
- Grep `LPSandbox|LPModTools|LifePlaySandbox` sur `Source\LifePlay\LPCityMaps*` : aucun résultat. Grep `LPModInfo|#include "LPMod` : une occurrence en commentaire (`LPCityMapsWindow.h:2`) et `LPCityMapsSubsystem.cpp:21` (`#include "LPModGuard.h"`).
- Glob `**/LPModGuard.h` sous `Source` : `Source\LifePlay\LPModGuard.h`, dans le module du jeu (pas l'addon).
- `LifePlay.Build.cs` lu en entier (63 l.) : aucune dépendance LPSandbox ni LPModTools ; dépendances E5 `"HTTP", "OpenSSL", "libzip"` à `:49`.
Résultat : **établi**.
### 3.6 Critère i : `DirectoriesToAlwaysStageAsUFS`
Grep `DirectoriesToAlwaysStageAsUFS|LPModGuard|LPSandbox|LPModTools` sur `Config\` : `Config\DefaultGame.ini:75` = `+DirectoriesToAlwaysStageAsUFS=(Path="Data")`.
Résultat : **établi**.
### 3.7 `Mods\` et licences
- Glob `*` sous `Mods\` : `No files found` (dossier présent, vide).
- Glob `*` sous `Content\Data\Licenses\` : `Content\Data\Licenses\OpenStreetMap_Geodata_License.txt`, `Content\Data\Licenses\Vinfamy_License.txt` (deux fichiers, aucun autre).
### 3.8 État git (lecture seule : `git status --short`, `git diff --stat`)
```
M Config/DefaultGame.ini
M Source/LifePlay/LifePlay.Build.cs
?? Content/Data/
?? Source/LifePlay/LPCityMapsDownload.cpp
?? Source/LifePlay/LPCityMapsDownload.h
?? Source/LifePlay/LPCityMapsSubsystem.cpp
?? Source/LifePlay/LPCityMapsSubsystem.h
?? Source/LifePlay/LPCityMapsWindow.cpp
?? Source/LifePlay/LPCityMapsWindow.h
Config/DefaultGame.ini | 1 +
Source/LifePlay/LifePlay.Build.cs | 8 ++++++++
2 files changed, 9 insertions(+)
```
Résultat : aucun fichier hors périmètre parmi les fichiers E5 ; `Mods\` absent de `git status` (vide, § 3.7). Pas de `Blueprint`, pas de fichier de `Tools\`.
### 3.9 Dates d'écriture et ordre compilation / modification
```
2026-10-22 16:49:22 6836 Source\LifePlay\LPCityMapsDownload.h
2026-10-22 17:27:49 42383 Source\LifePlay\LPCityMapsDownload.cpp
2026-10-22 16:55:24 2530 Source\LifePlay\LPCityMapsWindow.h
2026-10-22 17:10:54 20313 Source\LifePlay\LPCityMapsWindow.cpp
2026-10-22 17:11:35 7214 Source\LifePlay\LPCityMapsSubsystem.h
2026-10-22 17:12:39 30413 Source\LifePlay\LPCityMapsSubsystem.cpp
2026-10-22 17:12:50 3300 Source\LifePlay\LifePlay.Build.cs
2026-10-22 17:12:50 693 Content\Data\LPCityMaps.json
2026-10-22 17:29:09 6346 Saved\Logs\portage\MAPDL1-E2T_Build_20261022-172856.log
2026-10-22 17:31:09 2780 Saved\Logs\portage\MAPDL1-E2T_Build_20261022-172922.log
```
Résultat : la dernière écriture d'un fichier E5 (17:27:49) précède le début de la compilation éditeur du journal 172856 (17:28:56 d'après son nom). La compilation porte donc sur le contenu actuel. Les fichiers modifiés après la compilation : aucun.
### 3.10 Recomptage des journaux de compilation (Grep, sans `Build.ps1 -FromLog`)
Commande : Grep `error C|error LNK|warning C|Result:|Total execution time|Using Visual Studio` sur les deux journaux.
```
MAPDL1-E2T_Build_20261022-172856.log (éditeur)
33:Using Visual Studio 14.50.35739 toolchain (…\MSVC\14.50.35717) and Windows 10.0.22621.0 SDK (…)
52:Result: Succeeded
53:Total execution time: 12.02 seconds
MAPDL1-E2T_Build_20261022-172922.log (jeu Development)
14:Using Visual Studio 14.50.35739 toolchain (…\MSVC\14.50.35717) and Windows 10.0.22621.0 SDK (…)
38:Result: Succeeded
39:Total execution time: 105.68 seconds
```
Résultat : 0 `error C`, 0 `error LNK`, 0 `warning C` dans les deux journaux. Concordance avec `MAPDL1-E2T-BUILD.md` § 4 (lignes 52-53 et 38-39, `Result: Succeeded`). Les chiffres du résumé E2T (0 erreur, 0 avertissement compilateur, 1 et 9 unités) ne sont pas recomptés ici : ce recomptage porte sur les lignes d'erreur et de résultat.
### 3.11 Correctif `UI` : diff contre l'instantané E2T (seule différence)
Commande : `git diff --no-index -- "…\MAPDL1-E2T\Source\LifePlay\LPCityMapsDownload.cpp" "…\Source\LifePlay\LPCityMapsDownload.cpp"` (MD5 de l'instantané : `0F5D9DDD3614CFE23FCCD0EA55A3B7B1`, d'après `MAPDL1-E2T\manifest.csv` et `Get-FileHash`).
```
@@ -14,10 +14,13 @@
#include "Misc/Paths.h"
// OpenSSL (EVP, SHA-256) et libzip : avant les en-tetes Windows …
+// UI : le typedef d'OpenSSL heurte l'espace de noms UI du moteur (C2365, E2 bis) ; meme parade que BuildPatchServices/Crypto.cpp.
+#define UI UI_ST
THIRD_PARTY_INCLUDES_START
#include "openssl/evp.h"
#include "libzip/zip.h"
THIRD_PARTY_INCLUDES_END
+#undef UI
#if PLATFORM_WINDOWS
```
Résultat : **établi**. Trois lignes ajoutées (commentaire, `#define UI UI_ST` avant les en-têtes OpenSSL, `#undef UI` après `THIRD_PARTY_INCLUDES_END`), aucune ligne retirée, aucune autre modification. Les lignes 16 à 25 du fichier actuel contiennent ce correctif et rien d'autre. Code de sortie `git diff --no-index` : 1 (différences, pas une erreur).
### 3.12 Diffs des fichiers suivis contre les instantanés E5 (décompte recalculé)
```
21 3 …\MAPDL1-E5\Source\LifePlay\LPCityMapsSubsystem.h => …\Source\LifePlay\LPCityMapsSubsystem.h
109 5 …\MAPDL1-E5\Source\LifePlay\LPCityMapsSubsystem.cpp => …\Source\LifePlay\LPCityMapsSubsystem.cpp
4 0 …\MAPDL1-E5\Source\LifePlay\LifePlay.Build.cs => …\Source\LifePlay\LifePlay.Build.cs
2 2 …\MAPDL1-E5\Content\Data\LPCityMaps.json => …\Content\Data\LPCityMaps.json
```
Concordance avec `MAPDL1-E5-IMPL.md` § 1 : +21 −3, +109 −5, +4 −0, +2 −2 : identique. Diff du JSON : seules les lignes 7 et 11 (`"fichier"`) changent ; `titre` inchangé (voir § 4).
## 4. Diff lu en entier (fichiers, compte)
| Fichier | État | Compte | Lu |
|---|---|---|---|
| `Source/LifePlay/LPCityMapsDownload.h` | neuf (`??`) | 180 l. | en entier |
| `Source/LifePlay/LPCityMapsDownload.cpp` | neuf (`??`) | 1406 l. (1403 + 3 du correctif) | en entier ; diff E2T lu (§ 3.11) |
| `Source/LifePlay/LPCityMapsWindow.h` | neuf (`??`) | 67 l. | en entier |
| `Source/LifePlay/LPCityMapsWindow.cpp` | neuf (`??`) | 585 l. | en entier |
| `Source/LifePlay/LPCityMapsSubsystem.h` | neuf (`??`, E1 + E5) | 178 l. ; E5 : +21 −3 | en entier ; diff E5 lu (§ 3.12) |
| `Source/LifePlay/LPCityMapsSubsystem.cpp` | neuf (`??`, E1 + E5) | 946 l. ; E5 : +109 −5 | en entier ; diff E5 lu, 5 hunks (imports, `RestartRequired`, `SortGroup`, clic, `Deinitialize`, `Tick`, `DecorateRows`, `OpenCityWindow`, `MarkRestartRequired`) |
| `Source/LifePlay/LifePlay.Build.cs` | M | 63 l. ; E5 : +4 −0 ; contre HEAD : 8 insertions | en entier ; diff E5 lu |
| `Content/Data/LPCityMaps.json` | neuf (`??`) | 15 l. ; E5 : +2 −2 | en entier ; diff E5 lu |
| `Content/Data/Licenses/*.txt` (2) | neufs (`??`) | 155 l. et 5 l. | MD5 seulement (copies à l'octet) |
| `Config/DefaultGame.ini` | M | +1 contre HEAD | ligne 75 seule (Grep, § 3.6) ; diff E1 lu dans E3-VAL § 3.4 |
Ajouts de E5 hors fiche : aucun. Modifications faites par le validateur : aucune (§ Constats).
## 5. Verdict et contrôles de la fiche (§ 3 de la fiche)
| # | Critère (fiche E5 § 3 et § 2) | Verdict | Preuve (fichier:ligne) |
|---|---|---|---|
| a | Aucun `Delete` / `DeleteDirectory` / `Remove` (fichier) ; `Move` avec `Replace=false` | établi | § 3.4 : aucun `Delete` ; `Move` unique `LPCityMapsDownload.cpp:112`, `Replace=false` ; `Copy` `:1235` avec `false`. Réserve R-4 (moteur, destination partielle). |
| b | Installation complète refusée si `GIsEditor` : au clic et avant la pose | établi | `LPCityMapsDownload.cpp:773-778` (au clic, avant tout téléchargement) ; `:1268-1273` (avant la pose) ; `LPCityMapsWindow.cpp:457-465` (appel). |
| c | Membre avec `..` ou `.`, ou chemin absolu : refusé ; pose sous `ProjectDir` | établi, avec réserve R-1 | `:209-265` : `\` et `:` (`:218`), chemin absolu (`:224`), segments `..` et `.` (`:236`), préfixes autorisés (`:246-251`). Pose : `Root = ProjectDir` (`:445`), destinations `Root / Tree / Rel` (`:572`). Racines de l'archive vérifiées avant toute extraction (`:389-436`). |
| d | SHA-256 contrôlé avant toute pose ; écart : fichier déplacé (pas supprimé), URL suivante | établi | Pose seulement depuis `OnPackageReady` (`:1248-1263`), elle-même après `OnVerified` conforme (`:1138-1201`). Écart `:1158-1163` : `RejectFile` (déplacement dans `_rejet`, `:1388-1406`) puis `NextUrl` (`:1058-1069`). Cache : `:1165-1177`. |
| e | Seules les URL `https` acceptées (lecture de l'index) | établi | `LPCityMapsSubsystem.cpp:123-126` (`IsHttps`), `:415-433` (liens et page filtrés à la lecture), `LPCityMapsDownload.cpp:808-812` (contrôle repris au départ de l'essai). |
| f | Aucun texte de licence sans son fichier ; accord demandé avant le téléchargement | établi | `LPCityMapsWindow.cpp:71` (non coché à l'ouverture), `:199-207` (boutons de téléchargement actifs seulement si `bAccepted`), `:459` (`OnStart`), `:500-539` (texte chargé depuis `ProjectContentDir()/<fichier>`, `:523`, sinon `Licence text not found`, `:534`). |
| g | Les 2 fichiers de `Licenses` identiques à l'octet à `Licenses\` | établi | MD5 § 3.1 : `B1DAB513…` et `FB4E3868…` des deux côtés. |
| h | `LPCityMaps.json` valide (`Test-Json`), champs `fichier` existants sous `Content\` | établi | § 3.3 (`True`) ; `Content\Data\Licenses\*.txt` présents (§ 3.7) ; `LPCityMaps.json:7` et `:11`. |
| i | `DefaultGame.ini` : `+DirectoriesToAlwaysStageAsUFS=(Path="Data")` | établi | `Config\DefaultGame.ini:75` (§ 3.6). |
| 4 | Compilation sans l'addon : aucun include ni module LPSandbox / LPModTools | établi | § 3.5 : aucun. `LPModGuard.h` est dans `Source\LifePlay\` (jeu). |
**Verdict global : PASS-STATIC.**
Réserves (pas de contradiction, mais à trancher) :
- **R-1 (ouverte)** : `LPCityMapsDownload.cpp:236` ne refuse que `..` et `.`. Un segment fait seulement de points, comme `...`, passe. Le critère, tel qu'écrit, est satisfait ; le risque est que Windows normalise `...` et fasse remonter l'écriture `PoseDir / Member.Name` (`:473`) hors de `Saved/Downloads/<pack>/_pose`. Le comportement de normalisation n'est pas lu dans les sources : **incertain**. Essai qui tranche : un zip de test à segments `...`, posé dans un dossier jetable hors du jeu, ou la lecture de la normalisation Win32 dans les sources du moteur. Recommandation : refuser tout segment fait seulement de points.
- **R-4 (note)** : la copie du moteur supprime sa destination partielle en cas d'échec (`FileManagerGeneric.cpp:231-234`). La destination est neuve ; la source n'est jamais touchée.
- **R-5 (en jeu)** : si `RejectFile` échoue après un SHA faux (`:1161`), le `.part` reste et est re-vérifié à l'URL suivante (`:814-833`, `:1113-1136`). La pose reste bloquée par le contrôle ; c'est à confirmer en jeu.
Témoin en jeu : **à créer**. La fiche de tests `MAPDL1-E4-TESTS.md` ne contient aucun cas E5 (Grep `E5|LPCityMapsDownload|téléchargement|Témoin|COMMUN` sans résultat). Demande à l'orchestrateur : ouvrir le cas (fiche FIT, gabarit de `lp-doc`).
## 6. Points à confirmer par l'utilisateur (cases)
- [ ] R-1 : refuser aussi les segments faits seulement de points (`...`) ? La correction est à donner à une IMPL ; le validateur ne corrige pas.
- [ ] E-2 : accepter les entrées de dossier parents (`LifePlay/`, `LifePlay/Mods/`, `LifePlay/Content/`, `LifePlay/Content/Modules/`) ? La fiche § 2.4 disait « chaque nom commence par … ».
- [ ] E-1 : accepter `zip_source_win32w_create` + `zip_open_from_source(ZIP_RDONLY)` à la place de `zip_open` (fiche § 2.4 étape 2) ?
- [ ] Témoin en jeu : cas à créer pour E5 (R8) ; demande à l'orchestrateur.
- [ ] Ordre de commit E1, E5 et STM1 (V-14) : décision du gardien.
- [ ] `villes: []` dans `LPCityMaps.json` : aucune ville téléchargeable tant que l'index n'est pas généré ; l'essai en jeu demande un index d'essai (`Saved\LPCityMaps.json`).
Points qui ne se vérifient qu'en jeu (non rejoués, non mesurés) : V-6 Shipping (`comdlg32`), V-7 (licences dans le pak), V-8 (rendu), V-9 (redirections, `Range`, casse de `Content-Range`), V-10 (coupure, reprise, 200 sur reprise, SHA faux, miroir, recours), V-11 (pose, retour arrière, `_ancien`, « Restart required », montage au lancement suivant), V-12 (éditeur), V-13 (`Deinitialize`), R-1 (test de segments `...`), R-5 (`.part` corrompu), lecture de licence en build empaqueté (`FFileHelper` sur `ProjectContentDir()`), sélecteur « Choose file » (`GetOpenFileNameW`, jamais utilisé dans le moteur, `MAPDL1-E5-IMPL.md` Constats 1).
Tours : 8 / 40 (décompte de l'agent au moment de l'écriture, ce tour compris ; `FicheStats` non lancé)
## Constats
**Écarts à la fiche** (déclarés par l'IMPL, vérifiés) :
- E-1 : `zip_source_win32w_create` (`LPCityMapsDownload.cpp:274`) puis `zip_open_from_source(…, ZIP_RDONLY, …)` (`:281`), au lieu de `zip_open`. Non contraire au critère c. Décision § 6.
- E-2 : dossiers parents admis (`:252-262`), au lieu du refus littéral de la fiche § 2.4. Non contraire au critère c (aucun `..`, `.` ni chemin absolu). Décision § 6.
- E-3 : pose fichier par fichier (`:523-586`, `IFileManager::Move` un fichier à la fois). Établi.
- E-4 : refus `GIsEditor` au clic (`:773`) et avant la pose (`:1268`), plus tôt que l'étape 1 de la pose. Même résultat. Établi.
- E-5 : surveillance de Téléchargements démarrée à l'entrée du recours (`:1076`, `LPCityMapsWindow.cpp:553`). Établi.
- E-6 : statut HTTP jugé à la fin (`:915-916`, `:930`), sans `OnStatusCodeReceived`. Établi.
**Choix C-1 à C-12** : revus, aucun ne contredit une règle de la fiche. C-12 (fichier du joueur copié, jamais déplacé : `:1224-1235`) est conforme à la fiche § 2.5.
**Modifications faites par le validateur sur la copie** : aucune. Commandes de lecture seulement (`Get-FileHash`, `FileCheck.ps1`, `Test-Json`, `git status`, `git diff --stat`, `git diff --no-index`, Grep, Glob, Read). Une commande Bash a été refusée par le crochet `ecriture-gardien` (accent grave dans la commande, aucun effet sur les fichiers) ; elle a été relancée sans ce caractère. Seul fichier écrit : ce livrable.
**Non mesuré** : compilation (non relancée, par consigne), `Build.ps1 -FromLog` (non lancé, § en-tête), `LPTestStringCompat` (commandlet interdit), `LogStats` (aucun journal de jeu), réseau, tout comportement en jeu.
**Fichiers à commiter** : aucun. La VAL ne commite pas ; le livrable `MAPDL1-E3B-VAL.md` reste hors dépôt jusqu'à décision du gardien.
**À verser** : aucun nouveau (le piège du recomptage sans `Build.ps1 -FromLog` est déjà versé par `MAPDL1-E3-VAL.md`, lp-validate § 2).
**Suite** : orchestrateur doit trancher R-1, E-1, E-2 (§ 6), ouvrir le cas témoin E5 (R8), et programmer E2 bis (compilation déjà faite par E2T) ou les essais en jeu ; état : code écrit et compilé à code 0 (E2T-BUILD), validation statique PASS-STATIC, jeu non testé.