LifePlay-Revival/Docs/Migration/etat/CAM/CAM-B2g-VAL.md

248 lines
20 KiB
Markdown
Raw Normal View History

Fiche CAM-B2g-VAL — Niveau N1 — Modèle prévu non précisé par la fiche | utilisé claude-sonnet-5-5 — Agent lp-validator (A-VAL) — Skills sk-protocol, sk-recount, debug-verification, lp-validate
# CAM-B2g-VAL : validation de B2g et B2h (Room) et du témoin C2 complété (C, C++) (2026-10-13)
Copie `D:\Game\LifePlay-master 5.8`, branche `ue5.8` (`git branch --show-current`). Validateur distinct de l'auteur
(IMPL : `lp-mcp-bp`). Aucun asset, code ni doc validée modifié. Éditeur fermé avant, entre et après les commandlets.
**Verdict global : PASS pour Room (V5, V6, MD5) ; PASS-STATIC pour le C++ (C), non compilé par cette VAL.**
## 1. Fiches amont relues
- `Docs\Migration\etat\CAM\CAM-B2g-IMPL.md` (rapport de l'auteur, lu en entier : 20 appels MCP, tableaux A et B, écart E1).
- `Docs\Migration\etat\CAM\CAM-COMMUN3-DIAG.md` : § 7 (l. 119-187, partie 1 de C1), § 8 (l. 189-236, géométrie de
`Wall`), § 10 (l. 272-340, A, B, C et D ; amendement E1 à la l. 299 : `IfThenElse_100` reste sur PO_8).
- Références : `CAM-B2f-VAL_LPDumpFunction_20261013-195332.txt` et `CAM-B2f-VAL_CompileAllBlueprints_20261013-195519.txt`
(journal `Saved\Logs\portage\CAM-B2f-VAL_CompileAllBlueprints_20261013-195519.log`).
- Sauvegarde : `D:\Game\LifePlay_Backup_5.5\CAM-B2g\` (`manifest.csv`, `Content\BPs\Room.uasset`,
`Source\LifePlay\LPCameraModeSubsystem.{cpp,h}`, `editeur\`).
- Partie D (`Walk`, STG) : hors périmètre de cette VAL (non relue).
## 2. Points à confirmer des IMPL (§ 5 de `CAM-B2g-IMPL.md`)
| # | Point | Résultat | Preuve |
|---|---|---|---|
| P1 | Room = `0c8eb59f…` ; GI = `e64b5b37…` et Person = `8668a47c…` inchangés | PASS | § 3 R1 et R9 |
| P2 | V5 : diff limité à `MakeArray_5` [2] ← 260.Wall | PASS | § 3 R3, `…-211708.txt:10083` |
| P3 | V5 : 1 nœud `CommutativeAssociativeBinaryOperator_60` (`BooleanOR`), A ← PO_8, B ← 269 | PASS | `:10888-10892` |
| P4 | V5 : conditions de 96 et 97 ← OR_60 | PASS | `:10627`, `:10636` |
| P5 | V5 : Room = 1261 nœuds | PASS | `:4833` |
| P6 | PO_8 → 91, 98, 99, 100 et OR_60 [0], plus 96 ni 97 | PASS | `:10186` |
| P7 | 269 → 77, 82, 84 et OR_60 [1] | PASS | `:9700` |
| P8 | then / else de 96 et 97 inchangés | PASS | `:10628-10629`, `:10637-10638` = lignes de la référence (absentes du diff) |
| P9 | `CompileAllBlueprints` éditeur fermé : 0 erreur ou avertissement nouveau sur Room | PASS | § 3 R4 à R6 |
| P10 | En jeu : C1 souris et flèches, C2 inchangé, D8 (caméra à 26 cm) | reporté (COMMUN-4, build empaqueté avec la partie D de STG) | non rejouable ici |
| P11 | (IMPL « Constats ») dossier d'instantané `CAM-B2g` : sous-dossier `Source` absent du manifeste | PASS, levé | § 3 R10 : il contient la sauvegarde des 2 fichiers C++ (cpp `1DE73AA9…`, h `84F9BA30…`) |
## 3. Critères rejoués (commande → résultat)
Toutes les commandes sont lancées depuis `D:\Game\LifePlay-master 5.8`. `UeState` relevé avant : `processus=0 editeur=0
compilation=0 shaders=0 jeu=0`, code 0.
### Room
**R1. MD5 de Room.**
`md5sum Content/BPs/Room.uasset` → `0c8eb59f55cb02ad2c4fa1413840b84b`. Sauvegarde `CAM-B2g\Content\BPs\Room.uasset` →
`f2b082d2911d9f7c7be60c2cf30ee6d5` (= manifeste, 6 378 021 octets). **PASS**.
**R2. V5, dump.**
```
powershell -NoProfile -Command "Set-Location 'D:\Game\LifePlay-master 5.8'; .\Tools\RunCommandlet.ps1 -Lot CAM-B2g-VAL -Commandlet LPDumpFunction -Args '-BP=Room -Fn=* -Pins -Exec' -EtatDir 'D:\Game\LifePlay-master 5.8\Docs\Migration\etat\CAM'"
code=0 duree=62s erreurs=0 avertissements=10822
resume : Docs\Migration\etat\CAM\CAM-B2g-VAL_LPDumpFunction_20261013-211708.txt (10943 lignes)
journal : Saved\Logs\portage\CAM-B2g-VAL_LPDumpFunction_20261013-211708.log
```
Référence : `CAM-B2f-VAL_LPDumpFunction_20261013-195332.txt` (10937 lignes, 10816 avertissements). Écart : +6 lignes dans les
deux comptes, cohérent avec le corps ci-dessous (voir R3).
**R3. V5, diff du corps.**
`cd Docs/Migration/etat/CAM; diff <(grep -v '^LogInit:' A) <(grep -v '^LogInit:' B)` (A = référence B2f, B = ce dump).
Sorties du diff, hors en-tête et sommaire (l. 1-110 : tableau des 100 signatures les plus fréquentes, dont l'ordre des
ex aequo change et dont le total passe de 10816 à 10822 ; c'est l'en-tête du fichier, pas le corps) :
| Ligne B | Différence | Attendu |
|---|---|---|
| 4833 | `=== Room :: EventGraph (1260 noeuds) ===` → `(1261 noeuds)` | 1261 (1260 + 1) : conforme |
| 9644 | `Wall -> 88.self, 438.self` → `…, K2Node_MakeArray_5.[2]` | 260.Wall → 88, 438, MakeArray_5 : conforme |
| 9700 | `CamC1On -> 77, 82, 84` → `…, K2Node_CommutativeAssociativeBinaryOperator_60.B` | 269 → 77, 82, 84, OR_60.B : conforme |
| 10083 (ajout) | `[2] -> K2Node_VariableGet_260.Wall` sous `MakeArray_5` | `[2]` ← 260.Wall : conforme |
| 10186 | PO_8 `ReturnValue -> 91, 98, 99, 100, OR_60.A` (avant : 91, 96, 97, 98, 99, 100) | 91, 98, 99, 100, OR_60 : conforme (E1) |
| 10627 | `IfThenElse_96` `Condition -> OR_60.ReturnValue` (avant PO_8) | conforme |
| 10636 | `IfThenElse_97` `Condition -> OR_60.ReturnValue` (avant PO_8) | conforme |
| 10888-10892 (ajout, 5 lignes) | `OR_60 appel KismetMathLibrary::BooleanOR()`, `self (vide)`, `A -> PO_8.ReturnValue`, `B -> VariableGet_269.CamC1On`, `ReturnValue -> IfThenElse_96.Condition, IfThenElse_97.Condition` | conforme |
Aucune autre ligne de corps ne diffère : 8 groupes de différences, aucune autre ligne `=== Room :: … ===` dans le diff
(les autres graphes de Room sont inchangés). Le dump ne contient pas de positions. Recompte des lignes : 6 modifiées
(4833, 9644, 9700, 10186, 10627, 10636) et 6 ajoutées (1 + 5), soit +6 au total, égal à 10943 − 10937. Lecture directe de
`…-211708.txt:10079-10083` (MakeArray_5 : `Array -> 459, 499, 505` inchangé, `[0]` 261, `[1]` 268, `[2]` 260) et
`:10625-10638` (96 et 97). **PASS**.
**R4. V6, CompileAllBlueprints.**
```
powershell -NoProfile -Command "Set-Location 'D:\Game\LifePlay-master 5.8'; .\Tools\RunCommandlet.ps1 -Lot CAM-B2g-VAL -Commandlet CompileAllBlueprints -EtatDir 'D:\Game\LifePlay-master 5.8\Docs\Migration\etat\CAM'"
code=3 duree=214s erreurs=25 avertissements=55
resume : Docs\Migration\etat\CAM\CAM-B2g-VAL_CompileAllBlueprints_20261013-211848.txt (954 lignes)
journal : Saved\Logs\portage\CAM-B2g-VAL_CompileAllBlueprints_20261013-211848.log
```
Code 3 et 25 lignes d'erreur, comme la référence (`…-195519.txt` : code 3, 207 s, 25 erreurs, 55 avertissements).
**R5. V6, comptes.**
- `grep -n "errors and" <journal>` → `3303:Compiling Completed with 3 errors and 0 warnings and 0 blueprints that failed to load.`
Référence (`…-195519.log:3302`) : même phrase.
- `grep -c "La compilation de .* a réussi" <journal>` → 420 ; référence : 420.
- `grep -n "La compilation de Room" <journal>` → `2021:… [0065,73] La compilation de Room a réussi ! [en 1 342 ms] (/Game/BPs/Room.Room)`.
- Erreurs : `grep "Error:" <journal> | grep -v "CR_FaceExpRig\|RLExpStruct\|graph function data for node @@" | wc -l` → 0
(25 lignes `Error:` au total, toutes `CR_FaceExpRig` / `RLExpStruct` ou le message sans nom d'actif `Could not find graph
function data for node @@`, présent à l'identique dans la référence).
**PASS**.
**R6. V6, diff contre la référence.**
`diff` des deux `.txt` (hors `LogInit:`, après retrait des durées `[en N ms]`, des horodatages `[nnnn,nn]` et du nom du
journal) : seules les lignes de durée changent, 7 lignes (GI 4 577 → 5 417 ms, PC, Person, StreetMap_Static, Room
1 327 → 1 342 ms, StandardMacros, ActorMacros), plus les 3 lignes d'en-tête (lot, date, journal). Les sections Erreurs (16
signatures) et Avertissements (42 signatures) sont identiques ligne à ligne. **PASS**.
### Fichiers de référence inchangés
**R9. MD5 finaux (après les deux commandlets).** Voir la section « Mesuré ». GI `e64b5b37c9ef0db7735de0d6e3bd7c1c`,
Person `8668a47c627f7a5254910cf0ac33b12a`, Room `0c8eb59f55cb02ad2c4fa1413840b84b` : inchangés par les commandlets. **PASS**.
**R10. Instantané.** `D:\Game\LifePlay_Backup_5.5\CAM-B2g\manifest.csv` : une seule ligne (Room, 6 378 021 octets,
`F2B082D2…`). Le dossier `Source\LifePlay\` de l'instantané contient `LPCameraModeSubsystem.cpp` (`1DE73AA9…`) et `.h`
(`84F9BA30…`) : c'est la sauvegarde de C, prise hors manifeste. **PASS**.
### C++ (C) : `Source/LifePlay/LPCameraModeSubsystem.cpp`
Fichier non suivi par git (`?? Source/LifePlay/LPCameraModeSubsystem.cpp` et `.h`, créés au lot CAM-B2c) : pas de
`git diff` possible, la comparaison se fait contre la sauvegarde.
**C1. MD5 et fins de ligne.**
`.\Tools\FileCheck.ps1 -Path Source\LifePlay\LPCameraModeSubsystem.cpp,….h,<sauvegarde cpp>,Content\BPs\Room.uasset`
```
Fins CRLF LF CR BOM MD5 Fichier
LF 0 386 0 - 61FB558202E9BB3F567BCEAA4BF241D3 Source\LifePlay\LPCameraModeSubsystem.cpp
LF 0 52 0 - 84F9BA303E1ABD171C506DFBB4ED9F63 Source\LifePlay\LPCameraModeSubsystem.h
LF 0 370 0 - 1DE73AA932AF2A056E1B8528CED4DCAB (sauvegarde du .cpp)
binaire … 0C8EB59F55CB02AD2C4FA1413840B84B Content\BPs\Room.uasset
fichiers=4 binaire=1 LF=3 alertes=0 introuvables=0 (code 0)
```
.cpp = `61FB5582…` attendu ; sauvegarde = `1DE73AA9…` attendu ; .h = `84F9BA30…` inchangé (= sauvegarde du .h).
LF partout, 0 CRLF, 0 CR seul, sans BOM, comme la sauvegarde. **PASS**.
**C2. Diff contre la sauvegarde** (`diff sauvegarde actuel`, 386 − 370 = +16 lignes) :
5 hunks de code (plus les lignes de commentaire), rien hors du code du DIAG § 10 C :
1. l. 46-48 : `const FName RoomC2Target(TEXT("C2Target"));` et `const FName GIWall(TEXT("Wall"));` (+ 1 commentaire), dans
l'espace de noms nommé `LPCameraModeLocal`.
2. l. 228-232 : `if (AActor* Wall = Cast<AActor>(LPCameraModeLocal::ReadObject(GI, LPCameraModeLocal::GIWall))) { Query.AddIgnoredActor(Wall); }`
juste après `Query.AddIgnoredActor(Cam)`.
3. l. 234 et 237 : `Probe` devient `[&](ECollisionChannel Channel, const FVector& Direction) -> FString` et le balayage
utilise `Head + Direction * WitnessProbeLength` (plus `Dir` capturé).
4. l. 246-255 : `Probe(ECC_Camera, Dir)`, `Probe(ECC_Visibility, Dir)`, puis `PC`, `Back`, `BackText = Probe(ECC_Visibility, Back)`,
`Target`, `TargetText`, `Offset`.
5. l. 265-266 : `UE_LOG` étendu.
Comparé au bloc du DIAG § 10 C (l. 309-330) : identique, hormis la ternaire de `TargetText` coupée en deux lignes et
quelques lignes de commentaire ajoutées. **PASS-STATIC**.
**C3. Conformité aux points demandés.**
| Point | Lecture | Verdict |
|---|---|---|
| `GIWall`, `RoomC2Target` ajoutés | l. 46, 48 | PASS-STATIC |
| `Wall` ignoré dans la requête | l. 229-232, après `AddIgnoredActor(Cam)` (l. 227) ; même liste que `MakeArray_5` + `GI.Wall` | PASS-STATIC |
| `Probe` prend la direction | l. 234 ; les 3 appels (l. 246, 247, 251) passent un 2e argument | PASS-STATIC |
| sonde arrière suit la rotation de contrôle du PC | l. 249-251 : `FRotator(0, ControlRotation.Yaw, 0)`, axe X, négatif ; repli `-Player->GetActorForwardVector()` si pas de PC | PASS-STATIC (que cet axe soit celui de la sonde 459 de Room est l'affirmation du DIAG § 8, non re-dérivée ici) |
| distance à `C2Target`, tête, décalage capsule | l. 252-255 (`FVector::Dist(Head, Target)`, `Head.X/Y`, `(Head − Player->GetActorLocation()).Size2D()`) ; `ReadVector` existe l. 77 et rend faux sinon → `illisible` | PASS-STATIC |
| `UE_LOG` : arguments et types | 10 spécificateurs dans le format (`%.0f`, `%+.0f`, `%s`, `%.0f`, `%.0f`, `%.0f`, `%s`, `%s`, `%s`, `%s`, compté par `grep -o '%[+.0-9]*[fsdi]' \| wc -l` = 10) pour 10 arguments (l. 266) : `Distance` (float), `CamLoc.Z - Head.Z` (double), `*TargetText`, `Head.X`, `Head.Y`, `Offset.Size2D()` (double), `*CameraText`, `*VisibilityText`, `*BackText`, `*BoxText`. Types alignés : réels pour `%f`, `*FString` pour `%s`. `FString::Printf("%.0f cm", FVector::Dist(...))` : double pour `%f` | PASS-STATIC |
| pas de nouvel include requis | `FRotationMatrix` : `Core/Public/Math/UnrealMath.h:41` inclut `Math/RotationMatrix.h`, lui-même inclus par `CoreMinimal.h:154` (déjà dans le .h, l. 12) ; `GetUnitAxis(EAxis::Type)` à `Math/Matrix.h:274` ; `Size2D` à `Math/Vector.h:585` ; `APlayerController` : `GameFramework/PlayerController.h` déjà inclus (.cpp l. 13), `GetControlRotation` vient d'`AController` ; `UWorld::GetFirstPlayerController` : `Engine/World.h` (l. 8). Précédent de `FRotationMatrix(...).GetUnitAxis(EAxis::X)` dans ce module : `LPDirectControlSubsystem.cpp:1025` | PASS-STATIC |
| pas de collision de noms | `PC` : local à `WitnessC2` (l. 249), autre `PC` local dans `ComputeLabel` (l. 273), fonctions distinctes ; `GIPC` est le nom de la constante de l'espace de noms (l. 34) ; `Back`, `Target`, `Offset`, `Wall`, `BackText`, `TargetText` : aucun autre emploi dans le .cpp (Grep) ; aucun membre homonyme dans le .h (relu en entier, 52 lignes) ; `GIWall`, `RoomC2Target` dans l'espace nommé `LPCameraModeLocal` (pas anonyme, risque C2374 de l'en-tête évité) | PASS-STATIC |
| fins de ligne LF, sans BOM | C1 | PASS |
**C4. Risques de compilation relevés** (aucun bloquant) :
- `FRotator(0.f, PC->GetControlRotation().Yaw, 0.f)` mélange `float` et `double` (UE 5.x : `FRotator` est en double) : conversion
implicite sans perte vers le constructeur `(T, T, T)`, aucune ambiguïté connue ; pas de précédent identique relevé dans le
module (le DIAG § 7 utilise la même forme pour `Walk`). Estimé sans risque.
- `FVector Target;` n'est lu que si `ReadVector` rend vrai : pas d'usage non initialisé.
- `[[nodiscard]]` sur `GetUnitAxis` : le résultat est utilisé.
- Ternaire `PC ? -FRotationMatrix(...).GetUnitAxis(...) : -Player->GetActorForwardVector()` : les deux branches sont des
`FVector` (le `-` unaire s'applique au résultat de `GetUnitAxis`, priorité postfixe) ; `Player` est non nul à ce point
(`GetMesh` a déjà exigé `IsValid(Player)`, l. 203-207).
- Non compilé par cette VAL (consigne : statique). La compilation reste à faire au build de COMMUN-4 (C et D ensemble).
## 4. Diff lu en entier
| Fichier | Lecture | Compte |
|---|---|---|
| `Content/BPs/Room.uasset` | dump complet comparé à la référence (R3), lignes lues dans le dump | 8 groupes de différences de corps, 1 nœud de plus (1260 → 1261), 0 autre ligne |
| `Source/LifePlay/LPCameraModeSubsystem.cpp` | diff contre la sauvegarde, plus lecture des l. 1-130 et 150-290 | 5 hunks de code, +16 lignes (370 → 386), 0 ligne hors DIAG § 10 C |
| `Source/LifePlay/LPCameraModeSubsystem.h` | MD5 = sauvegarde, relu en entier | 0 différence |
| `Content/BPs/GI.uasset`, `Content/BPs/Person.uasset` | MD5 seul | 0 différence avec l'attendu |
`git status --short` (hors `Docs/`) : `M` GI, Person, Room ; `M` `LPDebugSubsystem.{cpp,h}`, `LPDirectControlSubsystem.{cpp,h}`,
`LPOutdoorRoomSubsystem.{cpp,h}` (modifications d'autres lots/STG, hors périmètre, non relues) ; `D`
`Tools/claude/hooks/ecriture-gardien.py` ; `??` `LPCameraModeSubsystem.{cpp,h}`. Aucun fichier `Content/` ni `Source/`
inattendu. Les commandlets n'ont pas modifié d'asset (MD5 inchangés, § Mesuré).
## 5. Verdict
- **Room (B2g + B2h) : PASS.** V5 conforme à la liste attendue, 1261 nœuds, rien d'autre ; V6 identique à la référence
(3 erreurs, 0 avertissement, `CR_FaceExpRig` seulement, Room compilé avec succès) ; MD5 attendus.
- **C++ (C) : PASS-STATIC.** Conforme au DIAG § 10 C, LF sans BOM, formats et types cohérents, pas d'include manquant, pas de
collision de noms. Non compilé.
- Écarts à la fiche de VAL : aucun. Aucune réserve sur les livrables amont, sauf que l'IMPL ne comptait pas les nœuds (P5,
maintenant compté ici) ; l'incertitude de l'IMPL sur le sous-dossier `Source` de l'instantané est levée (P11).
## 6. Points à confirmer par l'utilisateur
- [ ] Compilation du C++ (`LPCameraModeSubsystem.cpp`) au build de COMMUN-4, avec la partie D (`Walk`, STG) dans le même build.
- [ ] P10, en jeu (build empaqueté) : C1, la souris et les flèches gauche/droite tournent la vue ; C2 inchangé ; D8, plus
de ligne `Temoin C2` sous 100 cm hors des rues étroites (la nouvelle ligne donne la cible C2, la tête, le décalage capsule
et la sonde vers l'arrière).
- [ ] Partie D (`Walk`, STG, `LPDirectControlSubsystem.cpp`, MD5 attendu `827F19C0…`) : hors de cette VAL.
## Mesuré
```
$ .\Tools\UeState.ps1 (avant)
processus=0 editeur=0 compilation=0 shaders=0 jeu=0 (code 0)
$ md5sum Content/BPs/Room.uasset Content/BPs/GI.uasset Content/BPs/Person.uasset Source/LifePlay/LPCameraModeSubsystem.cpp Source/LifePlay/LPCameraModeSubsystem.h (après les commandlets)
0c8eb59f55cb02ad2c4fa1413840b84b *Content/BPs/Room.uasset
e64b5b37c9ef0db7735de0d6e3bd7c1c *Content/BPs/GI.uasset
8668a47c627f7a5254910cf0ac33b12a *Content/BPs/Person.uasset
61fb558202e9bb3f567bceaa4bf241d3 *Source/LifePlay/LPCameraModeSubsystem.cpp
84f9ba303e1abd171c506dfbb4ed9f63 *Source/LifePlay/LPCameraModeSubsystem.h
$ md5sum <sauvegarde>/LPCameraModeSubsystem.cpp <sauvegarde>/LPCameraModeSubsystem.h <sauvegarde>/Content/BPs/Room.uasset
1de73aa932af2a056e1b8528ced4dcab *…/CAM-B2g/Source/LifePlay/LPCameraModeSubsystem.cpp
84f9ba303e1abd171c506dfbb4ed9f63 *…/CAM-B2g/Source/LifePlay/LPCameraModeSubsystem.h
f2b082d2911d9f7c7be60c2cf30ee6d5 *…/CAM-B2g/Content/BPs/Room.uasset
$ .\Tools\UeState.ps1 (après)
processus=0 editeur=0 compilation=0 shaders=0 jeu=0 (code 0)
```
Les 5 valeurs MD5 (Room, GI, Person, .cpp, .h) sont celles attendues par la fiche. `UeState` = 0 à la fin.
## Trace (TRACE)
```
Trace : Docs\Migration\etat\CAM\CAM-B2g-VAL_LPDumpFunction_20261013-211708.txt — Fiche CAM-B2g-VAL — 2026-10-13 21:17
Commande : RunCommandlet.ps1 -Lot CAM-B2g-VAL -Commandlet LPDumpFunction -Args '-BP=Room -Fn=* -Pins -Exec' (copie 5.8, éditeur 5.8 headless)
Environnement: copie D:\Game\LifePlay-master 5.8, branche ue5.8, Room 0c8eb59f…, éditeur fermé (UeState 0), machine calme
Attendu : 1261 noeuds EventGraph ; 8 groupes de différences listés au § 3 R3 ; rien d'autre
Obtenu : code 0, 62 s, 10943 lignes ; différences conformes
Lecture : les en-têtes de sommaire (l. 1-110) changent d'ordre pour les ex aequo : ne comparer que le corps
Trace : Docs\Migration\etat\CAM\CAM-B2g-VAL_CompileAllBlueprints_20261013-211848.txt — Fiche CAM-B2g-VAL — 2026-10-13 21:18
Commande : RunCommandlet.ps1 -Lot CAM-B2g-VAL -Commandlet CompileAllBlueprints
Environnement: idem ; éditeur fermé
Attendu : 3 errors and 0 warnings, CR_FaceExpRig seulement, Room compilé avec succès (référence B2f)
Obtenu : code 3 (attendu, comme la référence), 25 lignes d'erreur, 55 d'avertissement, "3 errors and 0 warnings", 420 compilations réussies
Lecture : le code de sortie 3 est celui de la référence (les erreurs CR_FaceExpRig d'un actif du moteur), pas un échec de Room
```
## Fichiers à commiter
- A `Docs/Migration/etat/CAM/CAM-B2g-VAL.md` (dépôt du jeu, branche ue5.8)
- A `Docs/Migration/etat/CAM/CAM-B2g-VAL_LPDumpFunction_20261013-211708.txt`
- A `Docs/Migration/etat/CAM/CAM-B2g-VAL_CompileAllBlueprints_20261013-211848.txt`
- (journaux `Saved/Logs/portage/CAM-B2g-VAL_*.log` : ignorés par git)
- Aucune modification d'asset ni de code par cette VAL.
Tours : 14 / 40
## Constats
- Piège de lancement : `powershell -NoProfile -File ./Tools/RunCommandlet.ps1 …` depuis Git Bash échoue (`Split-Path :
Impossible de lier l'argument au paramètre « Path », car il s'agit d'une chaîne vide`, `RunCommandlet.ps1:26`, `$PSScriptRoot`
vide). Lancement qui marche : `powershell -NoProfile -Command "Set-Location '<copie>'; .\Tools\RunCommandlet.ps1 …"`.
À verser : `lp-commandlets` (ou `lp-build` § 8).
- `FileCheck.ps1` n'accepte pas de chemins positionnels multiples ; utiliser `-Path 'a','b'`.
- Le dump `LPDumpFunction -Pins -Exec` reste comparable d'un lot à l'autre si l'on ne lit que le corps ; le sommaire (100
premières signatures) réordonne les ex aequo.