LifePlay-Revival/Docs/Migration/etat/CAM/CAM-B2p-E-VAL.md
edujiro5972 8084622450 LifePlay UE 5.8 : état de développement au 2026-10-19
Tickets : REP1-T4

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 22:57:42 +02:00

166 lines
20 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 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 <tag>`.
**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<double>` | 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 <instantané>\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<AActor>(Room)` avec `const UObject* Room` (`TickCoupleMouse`, `.cpp:752`) : `Runtime/CoreUObject/Public/Templates/Casts.h:88-89` `template <To, From> TCopyQualifiersFromTo_T<From, To>* Cast(From* Src)` donne `const AActor*`. `RoomActor` est déclarée `const AActor*` (`.cpp:752`) ; `IsHidden() const` l'accepte. PASS-STATIC.
- `Cast<UPrimitiveComponent>(ReadObject(...))` → `UPrimitiveComponent*` rangé dans un `const UPrimitiveComponent*` ; `Floor->Bounds.GetBox()` : `Core/Public/Math/BoxSphereBounds.h:226` `TBox<T> GetBox() const` (T = double), `FBox` = `TBox<double>` ; 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<SWidget> 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 (`<type> 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