Fiche STE-ORG5-V2 — Niveau N2 — Modèle prévu (modèle de l'agent lp-validator) | utilisé claude-sonnet-5-5 — Agent lp-validator — Skills lp-validate, sk-recount, sk-protocol (debug-verification préchargé) # STE-ORG5-V2-VAL : VAL statique, sans compilation, de l'affichage des récompenses ORG5 dans EquipMenu (I2a) (2026-10-14) Périmètre : lecture seule, sans compilation, éditeur, MCP, commandlet ni jeu. Seul fichier écrit : ce livrable. Branche `ue5.8`, HEAD `0745917`. Aucun refus du crochet. Tout verdict de compilation reste « probable ». Les MD5 sont relevés au début et à la fin de la VAL : identiques (voir 3, C0). ## 1. Fiches amont relues - Fiche `fiches\STE-ORG5-V2.md` (lue en entier) ; livrable IMPL `STE-ORG5-I2a-IMPL.md` (lu en entier : § 1.2 gardes, § 1.3 appels moteur, § 2 écarts E1-E11, § 3 instantané, § 4, § 5 points à vérifier) ; SPEC `STE-ORG5-I2-SPEC.md` (lue en entier, dont § 2.2, § 7 et « Décisions de l'utilisateur » Q-I2-1 à 4) ; VAL d'I1 `STE-ORG5-V1-VAL.md` (lue en entier : C2 à C10, D1, D2). La fiche `fiches\STE-ORG5-I2a.md` n'a pas été relue : la fiche V2 et l'IMPL en reprennent les consignes. - Code lu en entier : `Source\LifePlay\LPBonusRewardSubsystem.h` (165 lignes) et `.cpp` (1028 lignes). - Moteur 5.8 relu (`D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime`) : `CoreUObject\Public\UObject\UObjectGlobals.h:2059-2062` ; `UMG\Public\Components\TextBlock.h:103,114,148,156` ; `Widget.h:264,769,776` ; `Blueprint\WidgetTree.h:104-122` ; `Blueprint\UserWidget.h:1426,1524` ; `PanelWidget.h:28,36,59,122` ; `VerticalBox.h:30` ; `VerticalBoxSlot.h:53,58,63` ; `CanvasPanelSlot.h:112,116,132,148` ; `Slate\Public\Widgets\Layout\Anchors.h:78` ; `SlateCore\Public\Styling\CoreStyle.h:51` ; `UnrealType.h:7815` (inclut `UObject/StrProperty.h`). Précédent du dépôt : `LPColorGradeSubsystem.h:53` (`TWeakObjectPtr` sur déclaration avancée `:20`). ## 2. Points à confirmer des IMPL (IMPL § 5) | Id | Point | Verdict | Preuve / raison | |---|---|---|---| | V5-2 | compilation 5.8 sans erreur ni avertissement nouveau | reporté (BUILD COMMUN-8) ; lecture : **probable** | Voir 3, C7 | | C-a | `TWeakObjectPtr` dans `FLPBonusRewardLine` sur déclaration avancée | PASS-STATIC (probable) | `.h:52-55` déclarations avancées, `.h:86-90` ; même forme que `LPColorGradeSubsystem.h:20,53` déjà compilé ; `TWeakObjectPtr` ne demande le type complet qu'à `Get()` / affectation, faits dans le `.cpp` qui inclut `Components/TextBlock.h` | | C-b | `FindObjectFast(Tree, BoxName)` à deux arguments | PASS-STATIC (probable) | `UObjectGlobals.h:2058-2062` : `FindObjectFast(UObject* Outer, FName Name, EFindObjectFlags = None, EObjectFlags = RF_NoFlags)` ; `Tree` (`UWidgetTree*`) se convertit en `UObject*` ; appel `.cpp:749` | | C-c | `ConstructWidget(UTextBlock::StaticClass())` et `(…, BoxName)`, `[[nodiscard]]` | PASS-STATIC (probable) | `WidgetTree.h:105-118` : `ConstructWidget(TSubclassOf = StaticClass(), FName = NAME_None)`, `NewObject(this, WidgetClass, WidgetName, RF_Transactional)` ; résultat utilisé aux `.cpp:621` et `:759` ; `UClass*` se convertit en `TSubclassOf` | | C-d | `GetPropertyValue(const void*)` sur `FStrProperty`, `FNameProperty`, `FTextProperty` (`.cpp:227-235`) | PASS-STATIC (probable) | `UnrealType.h` (via `TPropertyTypeFundamentals`, statique), `UObject/TextProperty.h` inclus `.cpp:19`, `StrProperty.h` inclus par `UnrealType.h:7815` ; `Item` est un `const void*` ; `.ToString()` sur `FName` et `FText` | | C-e | `Equip->Slot.Get()`, `Cursor->WidgetTree.Get()`, `FCoreStyle::GetDefaultFontStyle("Regular", float)` | PASS-STATIC (probable) | `Widget.h:264` `TObjectPtr Slot` (`Get()` existe) ; `UserWidget.h:1524` `TObjectPtr WidgetTree` ; `CoreStyle.h:51` `GetDefaultFontStyle(const FName, const float, const FFontOutlineSettings& = …)`, `"Regular"` se convertit en `FName` | | C-f | `RemoveLine` et `RewardFont` dans l'espace de noms nommé `LPBonusReward`, pas de C2374 | PASS-STATIC (probable) | Grep `FLPBonusRewardLine\|namespace LPBonusReward\|ULPBonusRewardSubsystem` sur `Source` : 33 occurrences, dans les deux fichiers seulement ; chaque fonction définie une fois | | V5-3 | 0 `AddToViewport`, `AddViewportWidgetContent`, `CreateWidget`, `UButton` dans le `.cpp` | **PASS** | Grep du motif exact de la SPEC sur le `.cpp` : `No matches found` ; `GetWidgetFromName` (`.cpp:57,674`), `EquipMenu` (`:37`) et `LPBonusRewardBox` (`:39`) présents (l'IMPL cite un motif combiné qui sortait ces lignes ; le motif de la SPEC ne sort rien) | | V5-4 | création des widgets seulement dans `ShowAppliedReward` / `EnsureRewardBox` | **PASS** | Grep `NewObject\|ConstructWidget` : `ConstructWidget` aux `.cpp:621` (dans `ShowAppliedReward`) et `:759` (dans `EnsureRewardBox`, seul appel `:606`) ; `ShowAppliedReward` seul appel `:576` (dans `OnOrgasm`, donc `FirePending`) ; `Poll` n'appelle que `ClearRewardDisplay` (`:429`, `:440`), `Initialize` rien | | V5-5 | affichage après `ModifyStat` réussi et après le retour `bDisabled` | **PASS** | `bDisabled` : `.cpp:543-547` retour avant `Pick` ; `ModifyStat` `:567-570` (retour si faux) ; journal `:571` ; `ShowAppliedReward` `:576` ; format `Bonus : %s %s %+.1f` (`:627`) = format du journal (`:571`, `%+.1f`) | | V5-6 | `GI.Cursor` → `GetWidgetFromName("EquipMenu")` → `Cast` ; police 16, contour (2, noir 0,8), marge (10, 5, 10, 0) ; 500 seulement si inférieur | **PASS-STATIC** | `.cpp:647-668` (`ReadObject` + `Cast`), `:674-675` ; police `:55-62` (taille `:59`, contour `:60`, `FFontOutlineSettings(2, FLinearColor(0,0,0,0.8))`) ; marge `:633` ; hauteur `:713-717` (`Size.Y < 500` seulement) | | V6-1 à V6-8, V6-5, V6-7 | rendu, journaux, remplacement, fin de scène, `bDisabled`, 0 plantage | reporté (essai en jeu V6 du build COMMUN-8) | Hors périmètre d'une VAL statique ; lecture du code : voir 3, C3 à C5 | | V6-2 | journal `affichage dans EquipMenu (classe VerticalBox, 4 enfants)` puis `hauteur d'EquipMenu portee de 350 a 500` | reporté (V6) ; code conforme | `.cpp:794-799` (une fois par session, compte pris après `AddChild` : 3 enfants + la case) ; `:717` à chaque agrandissement | | Mise en page | `ScrollBox_3` (Fill) partage la place avec la case (Fill), même vide | reporté (V6) | Voir D2 | | Pause | le délai de 20 s court en temps réel | PASS-STATIC (constaté dans le code) | `FPlatformTime::Seconds` (`.cpp:638`, `:811`) : insensible à la pause du jeu, annoncé IMPL 1.4 | ## 3. Critères rejoués (contrôle → preuve → verdict) | # | Contrôle | Preuve | Verdict | |---|---|---|---| | C0 | Périmètre et empreintes | `git -C 'D:/Game/LifePlay-master 5.8' status --porcelain -- Content Source Config` → **18 lignes** (`wc -l` : 18) = 5 `M` Content (`GI, PC, Person, Room, TopRight`) + 7 `M` Source (`LPDebug*` ×2, `LPDirectControl*` ×2, `LPOutdoorRoom*` ×2, `LifePlay.cpp`) + 6 `??` (`LPBonusRewardSubsystem.cpp/.h`, `LPCameraModeSubsystem.cpp/.h`, `LPSaveRelaunch.cpp/.h`) ; les deux fichiers du lot toujours `??`, rien d'autre, aucune ligne `Config`, `LifePlay.Build.cs` absent de la sortie (inchangé), `UMG` à `Build.cs:38`. `md5sum` au début et à la fin : `.h` `87177c7a53fb5b5cc946e904060a3aaa`, `.cpp` `16147626d2fa8a11dac8747cdbe12e9a` = valeurs de la fiche et de l'IMPL ; horodatages `.h` 09:33:17, `.cpp` 09:35:21 (2026-10-14, avant la fiche V2) | PASS | | C1 | Décisions Q-I2-1 à 4 | **Q-I2-1** lignes seules : un `UTextBlock` par ligne (`.cpp:621-635`), blanc `FLinearColor::White` (`:629`), police 16 contour 2 noir 0,8 (`:55-62`), `HAlign_Left`, marge `(10,5,10,0)`, ni en-tête ni bouton (Grep `UButton` : 0). **Q-I2-2** minuterie 20 s par ligne : `ExpireAt = Seconds() + 20.0` (`:638`, constante `:31`), relue à chaque tick de 0,1 s (`:413`, `:803-820`), retrait par `RemoveFromParent` (`:42-49`). **Q-I2-3** 500 si inférieur : `:713-717` (`Size.Y` strictement inférieur à 500, `SetSize(X, 500)`). **Q-I2-4** `bDisabled` coupe tout : retour `:543-547` avant `Pick`, `ModifyStat` et `ShowAppliedReward` | PASS-STATIC | | C2 | Écarts E1-E11 | E1 voulu (Q-I2-2). E2 `ConstructWidget` au lieu de `NewObject` : même `NewObject` à l'intérieur (`WidgetTree.h:117`), outer = arbre de `Cursor`, justifié. E3 recherche élargie de la case : exigée par la garde 2, justifié. E4 retrait des lignes suivies au lieu de `ClearChildren` à chaque affichage : même effet visible (`MaxRewardLines = 1`, `.cpp:613-617`), justifié. E5 hauteur seulement hors taille automatique / étirement vertical (`:705`) : prudence correcte (sinon `GetSize().Y` n'est pas une hauteur), justifié. E6 `bInScene` (`:584-589`) : cas non prévu, justifié. E7 `Deinitialize` ne retire pas les widgets : sûreté en fermeture, justifié. E8 sept clés d'avertissement : relues (`GI.Cursor` `:650`, `GI.Cursor.Value` `:660`, `Cursor.EquipMenu` `:678`, `EquipMenu.Slot` `:698`, `EquipMenu.Slot.Layout` `:707`, `LPBonusRewardBox.Type` `:764`, `EquipMenu.AddChild` `:777`) = 7. E9 police de repli (`:58`), justifié. E10 `Poll` vide l'affichage si `SexOn` absent (`:428-429`), justifié. E11 D1 / D2 d'I1 : voir C6. **Aucun écart n'est un défaut** ; aucun ne contredit une décision de l'utilisateur | PASS-STATIC | | C3 | Garde 1 : `Cursor` / `EquipMenu` introuvable → pas de plantage, un avertissement unique, récompense appliquée | L'affichage vient après `ModifyStat` et le journal (`.cpp:567-576`) : aucun retour d'affichage ne défait la récompense. Chemin : `FindCursor` (`:643-668`) → `ReadObject` faux : `FirstWarning("GI.Cursor")` puis `nullptr` ; `Cast` nul, invalide ou `WidgetTree` nul : `FirstWarning("GI.Cursor.Value")` puis `nullptr` (le test `!Cursor->WidgetTree` suit `IsValid`, pas de déréférencement nul) ; `FindEquipMenu` (`:670-686`) → `Cast` nul : `FirstWarning("Cursor.EquipMenu")` ; `GetNameSafe(nullptr)` sûr. `ShowAppliedReward` rend sans effet sur `nullptr` (`:595-604`). Clé permanente dans `Warned` : un seul avertissement par session et par cause, et un `Cursor` valide plus tard fonctionne (pas d'état bloquant). Hauteur : `Slot` absent ou pas un `UCanvasPanelSlot` → `FirstWarning("EquipMenu.Slot")`, retour, l'affichage continue (`:605-606`). `AddChild` nul → `FirstWarning`, retour `nullptr` (`:774-783`). **Garde 1 établie** (lecture) | PASS-STATIC | | C4 | Garde 2 : aucun ajout en double si `EquipMenu` est reconstruit | `EnsureRewardBox` (`:721-801`), ordre : (1) `RewardBox` faible valide et `GetParent() == Equip` : retour sans création (`:726-730`) ; (2) enfant d'`EquipMenu` nommé `LPBonusRewardBox` : repris (`:735-744`, `bAttached`) ; (3) objet de ce nom dans l'arbre de `Cursor` par `FindObjectFast` : repris, `RemoveFromParent` puis ré-ajout, **sans `NewObject` du même nom** (`:746-757`) ; (4) création seulement si rien n'existe (`:757-760`). Chaque reprise vide la case et la liste (`:791-792`). Les lignes sont des enfants de la case : une seule case par `EquipMenu`. Cas `Cursor` recréé : nouvel arbre, nouveau nom libre, une case créée, anciennes lignes oubliées (`RewardLines.Reset()`), sans fuite (ramasse-miettes). **Garde 2 établie** (lecture) | PASS-STATIC | | C5 | Garde 3 : minuteries nettoyées à la sortie de scène et dans `Deinitialize` | Sortie de scène : `Poll` → `SexOn` faux : `ClearRewardDisplay(true)` (`.cpp:434-441`), idem propriété absente (`:428-429`) ; la fonction retire chaque ligne (`RemoveLine`) et vide `RewardLines` (échéances = contenu du tableau, aucune autre minuterie : pas de `FTimerManager`, pas de seconde poignée) (`:822-838`). `Deinitialize` (`:263-273`) : `RemoveTicker(TickHandle)` d'abord (plus aucun passage de `Tick`, donc plus de lecture d'échéance), `ClearRewardDisplay(false)` (échéances vidées, widgets laissés au monde qui se ferme), `RewardBox.Reset()`. Aucun accès à un widget après `Deinitialize`. Cas limite : la case vide reste dans `EquipMenu` après la scène (voir D2). **Garde 3 établie** (lecture) | PASS-STATIC | | C6 | Non-régression d'I1 (contre `STE-ORG5-V1-VAL.md` C2-C9) | **Table** `.cpp:278-299` : 20 clés dans l'ordre ; tags relus : clés 1, 3, 4 vides (`perversion`, `prone_to_orgasm`, `attractiontoplayer`), `masochist` / `likes_rough` / `masochist-` {Aggressive, AggressiveFM}, `fitness` / `prone_to_orgasm-` {Penetration, Foreplay, Cum}, `likes_oral` 6 tags, `likes_handjob` 3 tags : identiques à la description de V1 C2. **Tirage** `Pick` `:358-403` : mélange Fisher-Yates `RandRange(i, LastIndex)`, `SetNum(min(20,10))`, filtre `Overlaps(…, true)`, règle `attractiontoplayer`, sortie à 3, `-` final retiré : inchangé. **Formule** `RewardChange` `:303-312` : ordre `Abs`, `MapRangeClamped(0,100,0,1.9)`, `2 - m`, `×10`, `FCeil`, `/10`, signe : inchangé ; `CheckFormula` `:314-338` : 8 cas inchangés. **H1** `Poll` `:417-519` : mémorisation au premier passage, hausse = 1 attente (`FireAt = +0,2 s`), baisse = resynchronisation, oubli des personnes sorties : inchangé hors les ajouts d'affichage (`bInScene`, `ClearRewardDisplay`). **Règle commune ORG4 / ORG5** : un incrément de `Sex_OrgasmCounts` = au plus un `Pending` = au plus une récompense (`OnOrgasm`, `Stats[0]`) = au plus une ligne ; `Endsex` sans `Cum` : aucun incrément, aucune ligne. **D1 corrigé** pour le nouveau code et les trois avertissements de `Poll` (`FirstWarning` `:423`, `:447`, `:466`, définition `:1011-1020`, `WarnOnce` réécrit `:1022-1028`) ; restent hors correction, comme annoncé IMPL § 4, les `WarnOnce(Key, Printf)` liés à un orgasme (`:489`, `:847`, `:858`, `:886`…), appelés une fois par orgasme au plus. **D2 corrigé** : `ReadStrings` `:205-239` accepte `FStrProperty`, `FNameProperty` ou `FTextProperty` (`return false` seulement si aucun des trois). **Reste d'I1** (`AttractionAllowed`, `IsInterestedIn`, `QueryStat`, `ModifyStat`, `PersonName` `:840-1009`) : appels et signatures conformes à V1 C6. Limite : la version I1 n'existe plus (IMPL § 3, aucune copie) ; la comparaison repose sur la relecture contre V1-VAL et la SPEC, pas sur un diff | PASS-STATIC | | C7 | Compilation probable (lecture) | **Includes** : `Blueprint/UserWidget.h`, `Blueprint/WidgetTree.h`, `Components/CanvasPanelSlot.h`, `PanelWidget.h`, `TextBlock.h`, `VerticalBox.h`, `VerticalBoxSlot.h`, `Styling/CoreStyle.h`, `UObject/TextProperty.h`, `UObject/UnrealType.h` (`.cpp:7-20`) ; `FSlateChildSize` / `ESlateSizeRule` via `Widget.h` → `SlateWrapperTypes.h` ; `FSlateFontInfo` / `FFontOutlineSettings` via `TextBlock.h`. **Déclarations avancées** `.h:52-55` suffisantes (pointeurs et `TWeakObjectPtr` seulement dans l'en-tête). **Signatures** relues à la source : `GetWidgetFromName(const FName&) const` (`UserWidget.h:1426`), `GetFont() const` rend `const FSlateFontInfo&` (`TextBlock.h:148`), `SetFont(FSlateFontInfo)` `:156`, `SetColorAndOpacity(FSlateColor)` `:114`, `SetText(FText)` `:103`, `AddChild(UWidget*)` rend `UPanelSlot*` (`PanelWidget.h:59`), `GetChildAt(int32) const` `:36`, `GetChildrenCount() const` `:28`, `AddChildToVerticalBox` rend `UVerticalBoxSlot*` (`VerticalBox.h:30`), `SetPadding(FMargin)` / `SetSize(FSlateChildSize)` / `SetHorizontalAlignment` (`VerticalBoxSlot.h:53,58,63`), `UCanvasPanelSlot::GetSize() const` / `SetSize(FVector2D)` / `GetAnchors() const` / `GetAutoSize() const` (`CanvasPanelSlot.h:116,112,132,148`), `FAnchors::IsStretchedVertical() const` (`Anchors.h:78`), `RemoveFromParent()` virtuelle sur `UWidget` (`Widget.h:776`), `GetParent()` (`:769`). **`FindObjectFast`** deux arguments (`UObjectGlobals.h:2059`). **Expression conditionnelle** `Sample ? Sample->GetFont() : FCoreStyle::GetDefaultFontStyle(…)` (`.cpp:58`) : lvalue `const FSlateFontInfo` contre prvalue `FSlateFontInfo`, résultat prvalue copiée dans `Font` : valide. `UE_LOG` : `%.0f` avec `double`, `%d` avec `int32`, `%s` avec `*FString` ou `const TCHAR*`. **Avertissements probables** : aucun masquage (C4456 / C4458) relevé (aucun membre nommé `Cursor`, `Box`, `Line`, `Equip`, `Size`, `Tree`, `Entry`, `Font`) ; aucun C4996 (aucune API dépréciée citée) ; `[[nodiscard]]` respecté. Compilation : reportée à BUILD COMMUN-8 | PASS-STATIC (probable) | | C8 | Sûreté UMG | Création par `Cursor->WidgetTree->ConstructWidget` (`:621`, `:759`) : outer = arbre de `Cursor` ; nom fixe `LPBonusRewardBox` avec `FindObjectFast` **avant** création (`:749`) ; pointeurs faibles seuls (`RewardBox`, `FLPBonusRewardLine::Line`) ; `IsValid` avant chaque accès (`:44-45`, `:658`, `:676`, `:727`, `:752`, `:762`) ; `RemoveFromParent` seulement si `IsValid` ; appels depuis `FTSTicker` sur le thread de jeu (`Tick` → `FirePending` / `ExpireRewardLines`), jamais dans la pile de l'événement `Cum` (SPEC R3) ; aucun accès après `Deinitialize` (ticker retiré en premier) ; `WidgetTree` testé avant `ConstructWidget` (`:658`) et `Tree` non nul pour `FindObjectFast`. Shipping : aucune macro éditeur, aucun `check` / `ensure`, aucun code de débogage ajouté ; `Verbose` pour le détail. Aucun `UFUNCTION`, aucun délégué lié à un widget (pas de gestionnaire de clic, pas de rappel après destruction) | PASS-STATIC | | C9 | CR et nom d'utilisateur | CR : `cat \| tr -cd '\r' \| wc -c` → `.h` **0** (165 lignes par `wc -l`), `.cpp` **0** (1028 lignes). Grep d'un nom d'utilisateur et d'un chemin de profil sur `LPBonusRewardSubsystem.*` (motif non recopié ici) : `Found 0 total occurrences across 0 files.` ; Grep du même motif sur ce livrable : rejoué après écriture (voir Constats) | PASS | ## 4. Diff lu en entier - Deux fichiers non suivis (`??`) : pas de diff contre un tag (`STE-ORG5-avant` ne couvre rien d'existant ; **la version I1 n'a pas été sauvegardée** avant I2a, IMPL § 3). Lus **en entier** : `.h` 165 lignes, `.cpp` 1028 lignes (comptes `wc -l` : 165 et 1028 = valeurs de l'IMPL). Aucun autre fichier de `Content`, `Source` ou `Config` ajouté ou modifié par le lot (C0, comparaison aux 18 lignes de l'état d'entrée de l'IMPL § 1.5). - Références `.cpp` de l'IMPL § 1 contrôlées sur 12 positions tirées : `:263-273` Deinitialize, `:413` Tick, `:417-446` Poll, `:574-576` OnOrgasm, `:579-641` ShowAppliedReward, `:643-668` FindCursor, `:670-686` FindEquipMenu, `:688-719` EnsureEquipMenuHeight, `:721-801` EnsureRewardBox, `:803-820` ExpireRewardLines, `:822-838` ClearRewardDisplay, `:1011-1028` FirstWarning / WarnOnce : toutes exactes. Références du `.h` (`:52-55`, `:86-90`, `:132-148`, `:158-164`) exactes. - Aucune trace de modification par script (fichiers rédigés avec les outils dédiés, horodatages 09:33 et 09:35). Ajouts hors SPEC : tous annoncés (E1-E11), aucun caché. ## 5. Verdict **PASS-STATIC** : les trois gardes de Big Boss sont établies par lecture (C3, C4, C5), les décisions Q-I2-1 à 4 sont tenues (C1), I1 est non régressé et D1 / D2 corrigés comme annoncé (C6), la compilation est probable (C7). Aucun défaut bloquant. Deux défauts mineurs (D1, D2), une limite de méthode (L1), et les points reportés au build COMMUN-8 et à l'essai V6. Défauts : | # | Gravité | Constat | Correctif proposé (non appliqué) | |---|---|---|---| | D1 | mineur (probabilité très faible) | `FindObjectFast(Tree, BoxName)` (`.cpp:749`) n'exclut pas un objet marqué à détruire : si un objet de ce nom est en attente de ramasse-miettes, `Cast` réussit mais `IsValid` est faux (`:762`) ; avertissement unique `LPBonusRewardBox.Type` (message inexact : il parle d'un objet « sans être une VerticalBox utilisable ») et aucun affichage jusqu'au ramassage. L'objet est un sous-objet de l'arbre : il n'est détruit que si l'arbre l'est, donc avec un `Cursor` déjà remplacé (estimé, non rejoué) | passer `EInternalObjectFlags` / `RF_BeginDestroyed` en exclusion, ou accepter pour l'alpha | | D2 | mineur (rendu, non établi) | La case `LPBonusRewardBox` reste dans `EquipMenu` après la fin de la scène et l'expiration des lignes (seules les lignes sont retirées, `:822-838`) ; son slot est `Fill` comme `ScrollBox_3` : la liste de bondage partage la place même quand la case est vide (IMPL § 5 « Mise en page »). Effet visible possible : `ScrollBox_3` plus petit à 500 de haut | à juger en V6 ; si gênant, mettre la case en `Auto` ou `Collapsed` hors ligne (`SetVisibility`) | Limite L1 (méthode, déclarée par l'IMPL § 3 et § 4) : aucun instantané avant I2a, `sk-change-safety` non invoqué ; la version I1 ne se récupère plus. Le repli SPEC § 3 `git restore` est impossible tant que le gardien n'a pas commité I1 + I2a ensemble (SPEC R7). Constat F-I2a-1 de l'IMPL, repris ici. ## 6. Points à confirmer par l'utilisateur (cases) - [ ] 1. Build COMMUN-8 : code 0, module `LifePlay` recompilé, 0 erreur, 0 nouvel avertissement sur les deux fichiers (V5-2, C-a à C-f). - [ ] 2. Essai V6 : ligne visible menu ouvert sous la grille d'objets, blanche à contour noir, alignée à gauche (V6-1) ; disparition seule à 20 s (V6-8) ; remplacement au second orgasme (V6-3) ; aucune ligne après la fin de scène (V6-4) ; `bDisabled=True` : ni case ni ligne (V6-5) ; 0 plantage, 0 `Accessed None`, aucun avertissement `Bonus :` de widget nouveau (V6-7). - [ ] 3. Journal V6-2 : une ligne `affichage dans EquipMenu (classe …, 4 enfants)` et `hauteur d'EquipMenu portee de 350 a 500` (le dump de l'arbre de `Cursor` est antérieur au resave U5, F-I2-6). - [ ] 4. Mise en page (D2) : liste de bondage (`ScrollBox_3`) lisible à 500 de haut avec la case vide ; décision si D2 doit être corrigé. - [ ] 5. Ticket groupé I1 + I2a au gardien avant toute autre fiche touchant les deux fichiers (L1). Non rejoué par cette VAL : compilation et UHT, `LPTestStringCompat`, `CompileAllBlueprints`, comportement en jeu (une ligne vue, durée de 20 s, hauteur 500 effective), type réel de `GI.Cursor` et d'`EquipMenu` au chargement, diff contre la version I1 (perdue), texte du fichier `Licenses`. Tours : 8 / 35 ## Constats - `Fichiers à commiter` : `A Docs/Migration/etat/ST/STE/STE-ORG5-V2-VAL.md` (dépôt du jeu, branche `ue5.8`). Aucun fichier source modifié par la VAL ; MD5 identiques avant et après. - Écart de méthode de ma part : une commande Bash de contrôle des CR contenait une redirection d'entrée vers le fichier nul malgré la consigne « aucun chevron » ; le crochet ne l'a pas refusée, sa sortie a été ignorée et les comptes de CR ont été relevés par la seconde commande de la même exécution (`tr -cd '\r' | wc -c`). Sans effet sur les fichiers. - À verser : `lp-validate` § 1 — contrôle du périmètre d'une VAL sur fichiers non suivis : `git status --porcelain -- Content Source Config` puis `wc -l` (18 ici) et `md5sum` au début et à la fin ; compter les CR par `cat | tr -cd '\r' | wc -c` sans aucun chevron. `lp-validate` § 3 (VAL de code UMG) — le motif de la SPEC (`AddToViewport\|…\|UButton`) et celui qu'une IMPL cite peuvent différer : rejouer celui de la SPEC.