Fiche CAM-B2p-E-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 # CAM-B2p-E-VAL : borne dure du couple pendant le sexe, VAL statique (2026-10-14, reprise incluse) Copie `D:\Game\LifePlay-master 5.8`, branche `ue5.8`. Aucune compilation, aucun éditeur, aucun MCP, aucun jeu. Rien n'a été modifié hors ce livrable. `LPCameraModeSubsystem.cpp` et `.h` sont non suivis par git (`??`) : la comparaison se fait à l'instantané, pas à `git diff `. **Verdict final (après reprise, § 7) : PASS-STATIC.** La première passe rendait FAIL (§ 5, B1 : local `Root` qui masque un membre). B1 est corrigé et le contrôle d'ombrage de tout le fichier (§ 7.3) ne trouve aucun autre masquage. La compilation reste à faire (COMMUN-10). ## 1. Fiches amont relues - `Docs/Migration/etat/CAM/CAM-B2p-E-IMPL.md` (lu en entier). - `Docs/Migration/etat/CAM/CAM-COMMUN9-DIAG.md` § 3 (causes) et § 4 (E1 à E4), § 5 (essais CAM-64 à CAM-68). - Précédents cités pour la méthode : `CAM-B2p-D-VAL.md:104` (contrôle d'ombrage « aucun local ne porte le nom d'un membre »), `CAM-B2r-VAL.md:75`. - Instantané d'avant : `D:\Game\LifePlay_Backup_5.5\CAM-B2p-E\Source\LifePlay\` (2 fichiers + `manifest.csv`). ## 2. Points à confirmer des IMPL (IMPL § 3) | Point | Résultat | |---|---| | Compilation : `AActor::IsHidden` | PASS-STATIC : `Engine/Classes/GameFramework/Actor.h:4523` `bool IsHidden() const { return bHidden; }` | | Compilation : `TNumericLimits` | PASS-STATIC : `Core/Public/Math/NumericLimits.h:270` (spécialisation `double`), `Max()` l. 279, `Lowest()` l. 284, `static constexpr` | | Compilation : `FBox(ForceInit)` | PASS-STATIC : `Core/Public/Math/Box.h:80` `explicit constexpr TBox(EForceInit)` ; `Min`, `Max` : `Box.h:39,42` | | Compilation globale (COMMUN-10) | **BLOCKED** (non compilé). B1 (C4458 attendu) est corrigé à la reprise ; ombrage de tout le fichier vérifié (§ 7.3) | | En jeu : `Box.Bounds.Max.Z` = dessus du sol (LPDebug −102,2) | reporté V7 (CAM-64 à CAM-68) | | En jeu : limites XY de `Box` couvrent tout le sol | reporté V7 | | En jeu : aucune pose légitime remontée à tort | reporté V7 (CAM-67) | ## 3. Critères rejoués (première passe ; les valeurs de la reprise sont en § 7) | # | Critère | Commande / lecture | Résultat brut (première passe) | Verdict | |---|---|---|---|---| | 1a | MD5 `.cpp` | `md5sum LPCameraModeSubsystem.cpp` | `6192495e9f25b0475654563538de8619` (annoncé alors `6192495E…8619`) ; **remplacé à la reprise, § 7.1** | PASS (périmé) | | 1b | MD5 `.h` | `md5sum LPCameraModeSubsystem.h` | `0edc1f76b7eec0d135ea046da2269be0` (annoncé `0EDC1F76…9BE0`) ; inchangé à la reprise | PASS | | 1c | Lignes | `wc -l` | `.cpp` 1163, `.h` 121 | PASS | | 1d | CR | `tr -cd '\r' \| wc -c` | `0` et `0` (LF) | PASS | | 1e | Instantané | `md5sum` + `wc -l` sur la copie d'avant | `.cpp` `d60632646bf1cf7d200e3bea833d8d72`, 1044 l. ; `.h` `6585d7f67a7be3aea377b8e93cfa14d8`, 112 l. | PASS | | 2a | Ampleur du diff | `git diff --no-index --numstat` | `.cpp` `121 2`, `.h` `9 0` ; 1044 + 121 − 2 = 1163 ; 112 + 9 = 121 | PASS | | 2b | Seuls ces 2 fichiers diffèrent de l'instantané | `diff -rq \Source\LifePlay Source/LifePlay` | `…Subsystem.cpp differ`, `…Subsystem.h differ` (autres lignes : « Only in », hors instantané) | PASS | | 2c | Contenu du diff | lecture en entier (voir § 4) | uniquement : 4 constantes, appel dans `TickSwitchKey`, `TickCoupleBounds`, lambda `TraceDown` + 4 déclarations, 6 membres `.h` | PASS | | 3 | Relecture C++ UE 5.8 | voir § 3.1 | un défaut en première passe (B1), corrigé (§ 7) | PASS-STATIC après reprise | | 4 | Logique (a à j) | voir § 3.2 | conforme, 3 remarques non bloquantes | PASS-STATIC | | 5 | Cohérence DIAG / IMPL | voir § 3.3 | écarts déclarés acceptables ; 2 écarts non déclarés (mineurs) | PASS-STATIC | ### 3.1 Relecture C++ (UE 5.8, `D:\Game\Launcher\Engine\UE_5.8\Engine\Source`) - **Ombrage d'un membre (B1)** : voir § 5 et § 7. - `Cast(Room)` avec `const UObject* Room` (`TickCoupleMouse`, `.cpp:752`) : `Runtime/CoreUObject/Public/Templates/Casts.h:88-89` `template TCopyQualifiersFromTo_T* Cast(From* Src)` donne `const AActor*`. `RoomActor` est déclarée `const AActor*` (`.cpp:752`) ; `IsHidden() const` l'accepte. PASS-STATIC. - `Cast(ReadObject(...))` → `UPrimitiveComponent*` rangé dans un `const UPrimitiveComponent*` ; `Floor->Bounds.GetBox()` : `Core/Public/Math/BoxSphereBounds.h:226` `TBox GetBox() const` (T = double), `FBox` = `TBox` ; même appel que B2p-D (`.cpp:862`). Ternaire `bFloorKnown ? …GetBox() : FBox(ForceInit)` : deux `FBox`. PASS-STATIC. - `Mesh->GetComponentLocation().Z`, `Character->GetMesh()` (const) : même motif que `.cpp:799-801`. `FVector::Dist` : `Vector.h:1015` statique ; `SizeSquared() const` : `Vector.h:571`. PASS-STATIC. - `FMath::Clamp/Min/Max` : arguments de même type (double/double/double ; float/float pour les cooldowns). `Pivot /= Couple.Num()` : motif déjà présent `.cpp:638`. PASS-STATIC. - `UE_LOG` (un spécificateur = un argument) : - « couple deplace hors prise » : 8 spécificateurs, 8 arguments. OK. - « pas de borne » : `%d`, `%s` ; `IsHidden()?1:0`, `*GetNameSafe(Floor)`. OK. - « couple ramene » : `%+.0f` ×3, `%.0f` ×2, `%d` ; `Correction.X/Y/Z`, `FloorTop`, `FloorTop + CoupleCeilingHeight` (double), `CoupleGrabMode` (`int32`, `.h:86`). OK. - `AxisValue(PC, …)` avec `PC` nul : `.cpp:211-214` renvoie 0.f. `bShift` : `PC && PC->PlayerInput && (…)`. OK. - Captures : `TraceDown` est `[&]`, déclarée après `bFloorKnown` et `FloorBox` (`.cpp:753-755`), lus seulement. OK. - Qualification : tous les appels d'aides de `TickCoupleBounds` et du lambda portent `LPCameraModeLocal::`. OK. - Nullité : `Couple.Num() > 0` avant `/=` ; `IsValid(Room)` avant `Room->IsHidden()` ; `IsValid(Floor)` avant `Floor->Bounds` ; `GI`, `World` testés ; `ReadActors` filtre par `IsValid` (`.cpp:199`). Dans `TickCoupleMouse`, `RoomActor` testé nul avant usage. OK. ### 3.2 Logique (4a à 4j) | Cas | Lecture | Verdict | |---|---|---| | (a) rien hors sexe, état oublié | `.cpp:508-513` : sans `SexOn`, `bHasLastPivot=false`, `bHiddenRoomWarned=false`, retour | PASS-STATIC | | (b) borne pendant les menus | `TickCoupleBounds` est appelée par `TickSwitchKey` (`.cpp:499`), sans retour anticipé avant l'appel (`.cpp:475-500`) et sans la garde `bMenuOnScreen` de `TickSexCamera` (`.cpp:607`) ; ticker à chaque image (`.cpp:328`) | PASS-STATIC | | (c) pas de borne si Room cachée / sans Box, une ligne par scène | `.cpp:542-555` ; `bHiddenRoomWarned` posé à la première ligne, remis à faux hors sexe | PASS-STATIC (N2) | | (d) XY : même marge que B2p-D | `.cpp:558` `CoupleFloorMargin` (30 cm), même test `> 2*Margin` que `.cpp:864` ; B2p-D borne déjà `Target` : rien à corriger pendant un glisser | PASS-STATIC | | (e) Z : remontée / descente, jamais les deux | `.cpp:575-582` : `if (Lowest < FloorTop - 5)` remonte de `FloorTop - Lowest` ; `else if (Highest > FloorTop + 350)` redescend (N3) | PASS-STATIC | | (f) un seul vecteur | `Correction` unique appliqué à toutes les `Couple` (`.cpp:583-588`), `Pivot += Correction` | PASS-STATIC | | (g) E2 | `.cpp:760-771` : impact + au-dessus du sol → `max(impact, FloorBox.Max.Z)` ; pas d'impact + au-dessus du sol → `FloorBox.Max.Z` ; hors du sol ou `bFloorKnown` faux : comportement précédent. Effet voulu (N1) : sans impact au-dessus du sol, `bGrabHasHeight` devient vrai | PASS-STATIC | | (h) témoin E4 | `.cpp:529-539` : seulement `CoupleGrabMode == 0`, `Dist > 5 cm`, `CoupleMoveCooldown <= 0` puis cooldown 1 s ; `PC` nul toléré | PASS-STATIC | | (i) déréférences nulles | voir § 3.1 | PASS-STATIC | | (j) boucle de rétroaction | le témoin compare le pivot lu en début d'image à `LastCouplePivot`, écrit en fin d'image **après** `Pivot += Correction` (`.cpp:597`, et `.cpp:552` pour la Room cachée) : la correction de l'image N n'est pas vue comme un déplacement à l'image N+1. Le glisser (`TickCoupleMouse` avant `TickCoupleBounds`, `CoupleGrabMode != 0` pendant la prise) met aussi `LastCouplePivot` à jour. Les chemins à Room invalide remettent `bHasLastPivot` à faux | PASS-STATIC | ### 3.3 Cohérence DIAG / IMPL - E1, E2, E3, E4 conformes au DIAG § 4. - Écarts déclarés (IMPL § 2) : champs E4 sur la ligne « hors prise » ; plafond 350 cm estimé ; borne aussi pendant une prise B2p-D (sans conflit). Acceptables. - Écarts non déclarés (mineurs, acceptables) : le DIAG place E1 « à la fin de `TickSexCamera` », l'IMPL l'appelle depuis `TickSwitchKey` après `TickSexCamera` (nécessaire : `TickSexCamera` sort en menu) ; la ligne E1 écrit `prise=%d` et non « source probable … ». - DIAG « Room.bHidden » : l'IMPL lit `AActor::IsHidden()` (= `bHidden` natif, `Actor.h:4523`). À confirmer en V7 que la variable Blueprint de Room est bien celle de `AActor`. ## 4. Diff lu en entier - `.h` : +9 lignes (`TickCoupleBounds`, `LastCouplePivot`, `bHasLastPivot`, `bHiddenRoomWarned`, `CoupleBoundsCooldown`, `CoupleMoveCooldown`, commentaires), 0 suppression. - `.cpp` : +121 / −2 en 6 hunks (`-U0`) : `@@ -130,0 +131,8` (4 constantes), `@@ -490,0 +499` (appel), `@@ -493,0 +503,98` (`TickCoupleBounds`), `@@ -641,0 +749,6` (E2, déclarations), `@@ -647 +760,3` et `@@ -651 +766,5` (`TraceDown`, 2 lignes remplacées). - Aucun ajout non demandé. Aucune édition par script déclarée ; LF inchangées (0 CR). ## 5. Verdict de la première passe : FAIL (corrigé, voir § 7) ### Défaut bloquant (première passe) **B1 — `Root` masque un membre de la classe : erreur C4458 attendue à la compilation** (ancien `.cpp:571-573`, dans `TickCoupleBounds`). - Le membre existe : `LPCameraModeSubsystem.h:114` `TSharedPtr Root;`. - Le projet traite l'ombrage en erreur : `Source/LifePlay.Target.cs:11` `DefaultBuildSettings = BuildSettingsVersion.V7` ; `CppCompileWarnings.cs:89-93` (moteur) défaut `WarningLevel.Error` dès V2, `/we4458` ; confirmé dans la ligne de commande réelle de la cible : `Intermediate\Build\Win64\x64\LifePlayEditor\Development\Core\SharedPCH.Core.Cpp20.h.obj.rsp:55` contient `/we4458`. `LifePlay.Build.cs` et les `.Target.cs` n'ont aucun réglage d'ombrage. - Établi : nom du membre, nom du local, `/we4458` actif. Estimé : le déclenchement de C4458 pour un local de fonction membre (non compilé). - État après reprise : **corrigé** (`RootZ`), voir § 7. ### Défauts non bloquants (inchangés) - **N1** (`.cpp:759-770`, E2) : `bGrabHasHeight` devient vrai dès que le pivot est au-dessus du sol sans impact ; voulu par le DIAG, à noter en V7. - **N2** (`.cpp:544-549`) : `bHiddenRoomWarned` n'est remis à faux qu'en sortie de sexe ; deux scènes consécutives sans passage `SexOn` faux n'écrivent qu'une ligne. - **N3** (`.cpp:575-582`) : couple dont les racines sont écartées de plus de 355 cm : seule la remontée est faite. - **N4** (`.cpp:859-869`, B2p-D, hors diff) : la borne XY du glisser n'a pas la garde « Room cachée » de `TickCoupleBounds`. Hérité de B2p-D. - **N5** : la borne XY ne s'applique que si `Box` fait plus de 60 cm dans les deux sens (comme B2p-D). ## 6. Points à confirmer par l'utilisateur - [x] Corriger B1 (renommer `Root` dans `TickCoupleBounds`) : fait, vérifié en § 7. - [ ] BUILD COMMUN-10 : 0 erreur, aucun avertissement C4456/C4457/C4458 nouveau. - [ ] V7 : `Box.Bounds.Max.Z` = dessus du sol (LPDebug −102,2) ; `Box` couvre tout le sol ; CAM-64 à CAM-68. - [ ] V7 : `Room.bHidden` du Blueprint est bien `AActor::bHidden` (ligne « pas de borne du couple (Room cachee=…) »). - [ ] V7 : hauteur de plafond de 350 cm (`CoupleCeilingHeight`) adaptée aux pièces du jeu. Non rejoué : compilation, `LPTestStringCompat`, ouverture de l'éditeur, essais en jeu (VAL statique demandée). ## 7. Reprise (2026-10-14) : correction de B1 et ombrage de tout le fichier Demande : revérifier la correction de B1, puis contrôler l'ombrage (C4458, C4456, C4457) sur **tout** le `.cpp`, B2r, B2p-C et B2p-D compris (jamais compilés). ### 7.1 Valeurs recomptées | Élément | Annoncé | Recompté | Commande | Verdict | |---|---|---|---|---| | MD5 `.cpp` | `FFF0FBB45D493B931B08780BF09547C8` | `fff0fbb45d493b931b08780bf09547c8` | `md5sum LPCameraModeSubsystem.cpp` | confirmé | | Lignes `.cpp` | 1163 | 1163 | `wc -l` | confirmé | | MD5 `.h` | `0EDC1F76…` (inchangé) | `0edc1f76b7eec0d135ea046da2269be0` | `md5sum` | confirmé | | Lignes `.h` | 121 | 121 | `wc -l` | confirmé | | CR | 0 | 0 et 0 | `tr -cd '\r' \| wc -c` | confirmé | | Diff chiffré | idem avant reprise | `.cpp` `121 2`, `.h` `9 0` | `git diff --no-index --numstat` | confirmé | | Fichiers qui diffèrent de l'instantané | 2 | 2 (`.cpp`, `.h`) | `diff -rq` | confirmé | ### 7.2 Les 3 substitutions Lecture de `.cpp:571-573` et recherche `\bRootZ?\b` : ``` 571: const double RootZ = Mesh ? Mesh->GetComponentLocation().Z : Person->GetActorLocation().Z; 572: LowestRoot = FMath::Min(LowestRoot, RootZ); 573: HighestRoot = FMath::Max(HighestRoot, RootZ); ``` Les autres occurrences de `Root` (l. 1112, 1130, 1140, 1144, 1147, 1156, 1161) sont le membre, dans `EnsureWidget`, `RemoveWidget`, `SetShown`, sans changement. Diff `-U0` revu (sortie rangée dans le dossier temporaire de session) : mêmes 6 hunks que la première passe (8, 1, 98, 6, 3, 5 lignes ajoutées ; 2 supprimées) ; la seule différence de contenu est `Root` → `RootZ` aux lignes 85-87 du diff (= `.cpp:571-573`). Établi pour la forme du diff et ces 3 lignes ; estimé pour « rien d'autre » (je n'ai pas conservé de copie de l'état d'avant la reprise : le MD5 seul ne le prouve pas, mais les compteurs de lignes et de hunks sont identiques). ### 7.3 Contrôle d'ombrage sur tout le fichier Méthode : 1. Membres du `.h` (35) : `TickHandle`, `SwitchKeyHandle`, `bSwitchKeyDown`, `LastEmptyView`, `WitnessCooldown`, `OcclusionCooldown`, `bCharGenSeen`, `CharGenRepairTimeout`, `C1Cooldown` (B2r) ; `bMenuOnScreen`, `SexKeysCooldown` (B2p) ; `CoupleGrabMode`, `bLeftWasDown`, `bRightWasDown`, `bGrabMoved`, `bGrabHasHeight`, `GrabHeight`, `GrabOffset`, `GrabMouseStart`, `GrabLastMouseX`, `GrabTurned`, `GrabCamera`, `GrabCameraLocation`, `GrabCameraRotation`, `bCursorWarned` (B2p-D) ; `LastCouplePivot`, `bHasLastPivot`, `bHiddenRoomWarned`, `CoupleBoundsCooldown`, `CoupleMoveCooldown` (B2p-E) ; `Root`, `Text`, `Viewport`, `ShownLabel`, `bShown` (B2c). Plus les fonctions membres (`Tick`, `ComputeLabel`, …). 2. Recherche par motif `Grep` d'une déclaration de l'un de ces noms (` NOM =|;|:|{|)|,`) sur tout le `.cpp` : **0 déclaration** (les 3 seules lignes remontées, 529, 851, 883, sont des usages `&& CoupleGrabMode ==`). Témoin positif du motif : 9 déclarations de `Hit`, `Margin`, `Floor` trouvées. 3. Lecture de toutes les fonctions du fichier (l. 26-1163) : paramètres, locaux, variables d'`for`/`if`, paramètres et locaux de lambdas, comparés aux membres, aux locaux englobants et aux paramètres. Résultat par fonction (aucun masquage) : | Fonction (lignes) | Noms déclarés | C4458 membre | C4456/C4457 local ou paramètre | |---|---|---|---| | `LPCameraModeLocal::*` (l. 146-320, fonctions libres) | `Container`, `Name`, `Prop`, `Inner`, `Array`, `Index`, `Actor`, `Out`, `Value`, `Down`, `Map`, `Settings`, `Keys`, `It`, `Widget`, `Visibility`, `ClassName`, `Menu`, `Focused` | sans objet (pas de classe) | aucun ; `ClassName` est local dans `MenuOnScreen` et paramètre dans `WidgetOnScreen`, jamais les deux | | `Initialize`/`Deinitialize` (323-337) | `Collection` | aucun | aucun | | `Tick` (339) | `Label`, `bMenu`, `World`, `PC`, `View`, `ViewText` | aucun | aucun | | `RepairAfterCharGen` (391) | params `Label`, `bMenu`, `DeltaTime` ; `GI`, `World`, `PC`, `View`, `bRoomCamera`, `RoomLabel` | aucun | aucun | | `WitnessC1` (440) | `GI`, `World`, `PC`, `Player`, `Mesh`, `Camera`, `Eyes`, `Distance`, `CameraRotation`, `YawGap`, `RoomObject` | aucun | aucun | | `TickSwitchKey` (475) | `GI`, `World`, `PC`, `Settings`, `bDown`, `Map` | aucun (`bSwitchKeyDown` ≠ `bDown`) | aucun | | `TickCoupleBounds` (502-599) | `GI`, `Room`, `Couple`, `Pivot`, `Person` (3 boucles sœurs), `World`, `PC`, `bShift`, `Moved` (bloc E4), `Floor`, `Box`, `FloorTop`, `Margin`, `Correction`, `LowestRoot`, `HighestRoot`, `Character`, `Mesh`, `RootZ` | aucun (`Root` n'existe plus comme local) | aucun : `World`, `PC`, `bShift`, `Moved` ne sont pas redéclarés dans la portée englobante | | `TickSexCamera` (601-695) | `Step`, `GI`, `World`, `PC`, `View`, `Forward`, `Right`, `Wheel`, `RoomObject`, `Room`, `Couple`, `Pivot`, `Person`, `bKeys`, `bGrabbing`, `SceneCamera`, `Angle`, `Offset`, `Distance`, `Direction`, `Rotation` (2 branches sœurs), `Look`, `Arrows`, `bShift`, `bButtons` | aucun | aucun | | `ReleaseCoupleGrab` (697) | — | aucun | aucun | | `TickCoupleMouse` (705-907) | params `GI`, `PC`, `View`, `Room`, `Couple`, `Pivot` ; `Input`, `bLeft`, `bRight`, `bLeftPressed`, `bRightPressed`, `World`, `bScene`, `Query`, `Wall`, `CamRoom`, `FloorComponent`, `RoomActor`, `bFloorKnown`, `FloorBox`, `MouseX`, `MouseY`, `bMouse` ; bloc prise : `bShiftHeld`, `MousePoint`, `bOnCouple`, `Person`, `Character`, `Mesh`, `Low`, `High`, `LowScreen`, `HighScreen`, `SurfaceZ`, `Aim` ; bloc dépose : `Rotation` ; blocs glisser/rotation : `Aim`, `Target`, `Floor`, `Box`, `Margin`, `SurfaceZ`, `Delta`, `Person`, `Turn`, `Offset`, `Rotation`, `Camera` | aucun (`Camera` ≠ `GrabCamera`, `Rotation` ≠ `GrabCameraRotation`, `Turn` ≠ `GrabTurned`) | aucun : les `Aim`, `SurfaceZ`, `Rotation`, `Person` sont dans des portées sœurs ; aucune variable de fonction n'est redéclarée dans un bloc imbriqué | | lambda `TraceCursor` (736) | `Out` ; `Origin`, `Direction`, `Hit` | aucun | aucun : la fonction englobante n'a ni `Origin`, `Direction` ni `Hit` | | lambda `TraceDown` (755) | `At`, `OutZ` ; `Hit`, `Start`, `End`, `bHit`, `bOverFloor` | aucun | aucun : la fonction englobante n'a aucun de ces noms (`SurfaceZ` ≠ `OutZ`) | | `LogSwitchKey` (909) | param `PC` ; `GI`, `RoomObject`, `Room`, `View`, `ViewportClient`, `Flag` ; lambda `Flag` : `Container`, `Name` | aucun (`ViewportClient` ≠ `Viewport`) | aucun | | `WitnessOcclusion` (927) | `GI`, `World`, `Room`, `Player`, `Cam`, `Mesh`, `Head`, `CamLoc`, `Query`, `Wall`, `Hit`, `Comp`, `MeshComp` | aucun | aucun | | `WitnessC2` (968) | `GI`, `World`, `Room`, `Player`, `Cam`, `Mesh`, `Head`, `CamLoc`, `Distance`, `Dir`, `Query`, `Wall`, `Probe`, `CameraText`, `VisibilityText`, `PC`, `Back`, `BackText`, `Target`, `TargetText`, `Offset`, `BoxText`, `BoxMin`, `BoxMax`, `Margin` ; lambda `Probe` : params `Channel`, `Direction` ; locaux `Hit`, `Owner` | aucun | aucun : `Hit` et `Direction` du lambda n'ont pas d'homonyme dans `WitnessC2` (`Dir` ≠ `Direction`) | | `ComputeLabel` (1046) | `GI`, `World`, `PC`, `View`, `Birdview`, `RoomObject`, `Room`, `PlayerCharacter`, `bC3`, `CamRoom`, `SceneCamera`, `bSceneCamera` | aucun | aucun | | `EnsureWidget` (1104) | `GI`, `ViewportClient`, `NewText`, `NewRoot` | aucun (`NewRoot` ≠ `Root`, `NewText` ≠ `Text`, `ViewportClient` ≠ `Viewport`) | aucun | | `RemoveWidget` (1138) | `ViewportClient` (if-init) | aucun | aucun | | `SetShown` (1154) | param `bShow` | aucun (`bShow` ≠ `bShown`) | aucun | Limites du contrôle (à dire) : - Les membres hérités (`UObject`, `USubsystem`, `UGameInstanceSubsystem`) n'ont pas été énumérés un par un : aucun nom déclaré ci-dessus n'est un nom de donnée connu de ces classes (`NamePrivate`, `ClassPrivate`, `OuterPrivate` sont les seuls à ressembler à des noms usuels, et aucun local ne les porte). Estimé, non établi. - C4459 (local qui masque un nom global ou d'un autre fichier en compilation unitaire) : non énuméré contre les globaux du moteur ; l'espace de noms nommé `LPCameraModeLocal` limite le risque (commentaire `.cpp:27-29`). Non établi. - Les macros `SNew`/`SAssignNew` (`.cpp:1119-1128`) déclarent leurs propres noms internes : non examinées. - Aucune compilation : tout reste « estimé » jusqu'au BUILD COMMUN-10. ### 7.4 Verdict de la reprise **PASS-STATIC.** B1 est corrigé, le diff contre l'instantané est inchangé hormis `Root` → `RootZ` (3 lignes), aucun masquage C4458, C4456 ou C4457 dans le fichier entier. Autres rubriques de la VAL inchangées (§ 3 à 6). Prochaine étape : BUILD COMMUN-10, critère : 0 erreur, aucun avertissement C4456/C4457/C4458 nouveau. Tours : 26 / 40