12 KiB
Fiche STG-C6b-VAL — Niveau N1 — Modèle prévu (agent lp-validator) | utilisé claude-sonnet-5-5 — Agent lp-validator — Skills sk-protocol, sk-recount, debug-verification, lp-validate
STG-C6b-VAL : validation statique du correctif C6-b, Scene_C comptée comme menu seulement si elle montre quelque chose (2026-10-14)
Verdict : PASS-STATIC (lecture et recomptes, aucune compilation, aucune exécution, aucun UE). Aucune écriture hors de ce livrable.
1. Fiches amont relues
Docs\Migration\etat\ST\STG\STG-C6b-IMPL.md(86 lignes, lu en entier).Docs\Migration\etat\ST\STG\STG-C6b.diff(117 lignes, lu en entier).D:\Game\LifePlay_Backup_5.5\STG-C6b\manifest.csvet les deux fichiers de l'instantané.Docs\Migration\etat\BOSS\COMMUN-3-TESTS.mdl. 25 (D10).- Pas d'autre IMPL amont dans cette fiche (le correctif entre avec M1e, déjà dans l'instantané).
2. Points à confirmer des IMPL
| Point (IMPL § 5) | Résultat |
|---|---|
Fenêtre A rejouée : ligne C6-b : boite Scene_C … sans contenu visible, ZQSD marche |
reporté (essai en jeu au prochain build commun, hors périmètre statique) |
D10 : boîte de scène visible, ZQSD sans effet, M1e : marche coupee par le menu Scene_C |
reporté (essai en jeu). Raisonnement statique au point 3.4 : PASS-STATIC sous réserve du risque R1 |
Structure réelle de /Game/UI/Scene (IMPL § 3, « estimé, non mesuré ») |
reporté, non lisible sans UE ; voir R1 |
3. Critères rejoués
3.1 MD5 (établi)
Commande : md5sum sur les fichiers actuels et sur l'instantané ; manifeste lu.
44ace47d29424101b4127ba12e789beb *Source/LifePlay/LPDirectControlSubsystem.cpp
ad60a24fb3e3075299c1f4ec5f087011 *D:/Game/LifePlay_Backup_5.5/STG-C6b/Source/LifePlay/LPDirectControlSubsystem.cpp
acff924ae6e03548546ef3fb2e430eb8 *Source/LifePlay/LPDirectControlSubsystem.h
979ae0ada261655cbbe9aefd6969e833 *D:/Game/LifePlay_Backup_5.5/STG-C6b/Source/LifePlay/LPDirectControlSubsystem.h
manifest.csv : cpp "AD60A24FB3E3075299C1F4EC5F087011" (46073 o) ; h "979AE0ADA261655CBBE9AEFD6969E833" (3082 o)
| Élément | IMPL | Recompté | Verdict |
|---|---|---|---|
| cpp actuel | 44ACE47D… | 44ace47d29424101b4127ba12e789beb | confirmé |
| h actuel | ACFF924A… | acff924ae6e03548546ef3fb2e430eb8 | confirmé |
| cpp instantané | AD60A24F… | ad60a24fb3e3075299c1f4ec5f087011 | confirmé |
| h instantané | 979AE0AD… | 979ae0ada261655cbbe9aefd6969e833 | confirmé |
3.2 Diff régénéré et périmètre (établi)
Commande : diff -u <instantané> <actuel> pour le cpp puis le h, lignes d'en-tête ---/+++ (horodatages) neutralisées, comparé à STG-C6b.diff sans CR : sortie DIFF-IDENTIQUE.
Recompte indépendant : grep -c '^+[^+]' du diff = 66 ; grep -c '^-[^-]' = 0. Conforme à l'IMPL § 2 (66 ajoutées, 0 retirée).
Lu en entier : 4 includes ; 3 fonctions (ShownUpToRoot, ShowsContent, EmptySceneSeen) ; EmptySceneSeen() = false; en tête de MenuReason ; bloc Scene_C dans la boucle ; journalisation dans WitnessMoveKeys ; membre bLoggedEmptyScene dans le .h. Rien d'autre que l'IMPL § 2 (aucun ajout non demandé).
Limite : l'instantané ne contient que les deux fichiers ; « rien d'autre n'a changé » est établi pour ces deux fichiers (diff identique), non pour le reste de l'arbre (les autres fichiers modifiés de git status viennent d'autres lots, non comparés ici).
3.3 Seule Scene_C est filtrée (établi, lecture de LPDirectControlSubsystem.cpp l. 689-715)
- Le filtre est
if (ClassName == TEXT("Scene_C") && !ShowsContent(Widget))(l. 707) : les 9 autres classes deMenuClasses(l. 58-62) passent àreturn ClassName;(l. 712) comme avant. - Panneau Clavier (l. 682-688) : placé avant la boucle, inchangé ; focus de saisie (l. 716-724) : après la boucle, inchangé.
break(l. 711) est dansfor (const TCHAR* Menu : MenuClasses); il sort de cette boucle seulement. La boucleTObjectIterator(l. 689) continue : le widget suivant est examiné.Scene_Cfigurant en dernier deMenuClasses, lebreakne saute aucune autre classe pour ce widget.- Seul effet de bord hors filtre :
EmptySceneSeen() = false;(l. 677) à chaque appel, et la ligne de journal ; aucun effet sur la valeur renvoyée.MenuReasonn'est appelé que parTick(l. 869), toutes les 0,25 s, avantWitnessMoveKeys(l. 872), d'où la lecture de l'indicateur à jour. - Note : si un widget
Scene_Cvide et un autre menu sont présents, l'indicateur reste levé alors que le menu coupe : seulement un message de journal (inexact mais sans effet sur la marche).
3.4 D10 par le code (estimé, raisonnement)
Une boîte avec un UTextBlock ou URichTextBlock non vide, ou un UButton (ou sous-classe : IsA), visible jusqu'à la racine : ForEachWidget parcourt tous les widgets de l'arbre (pas de court-circuit autre que bShown), bContent vrai, ShownUpToRoot vrai, donc ShowsContent vrai, MenuReason renvoie Scene_C. Cas de prudence confirmés dans le code (l. 641) : WidgetTree nul, Widget nul ou Depth > 8 renvoient vrai (compté comme menu). Une fois bShown vrai il n'est plus réécrit (retour anticipé l. 652).
Cas qui change : Scene_C Visible sans bouton ni texte non vide visible jusqu'à la racine, ou opacité de rendu du widget racine ≤ 0,01 (fenêtre A), ce que vise le correctif.
Risques (« une vraie boîte ignorée ») :
| # | Cas | Estimation |
|---|---|---|
| R1 | Boîte dont le seul contenu est dans un widget non couvert : UEditableText, UMultiLineEditableText, UImage seul, UCheckBox, UComboBox/liste, widget C++ propre |
Faible. Une boîte de dialogue de scène a des boutons de choix (UButton) ou un texte. Le focus de saisie reste couvert par la branche « focus » inchangée si un champ éditable a le focus. Non mesuré : la structure de /Game/UI/Scene n'est pas lue (comme dit en IMPL § 3). |
| R2 | UWidget::IsVisible() renvoie faux si le widget Slate n'est pas construit (Widget.cpp l. 395-403 : GetCachedWidget() invalide donne false) : un contenu pas encore construit est vu comme absent |
Faible, transitoire (au plus 1 cycle de 0,25 s), identique à l'effet de bord annoncé en IMPL § 3. |
| R3 | Texte non vide mais rendu invisible par autre chose que visibilité/opacité (alpha de couleur à 0, hors écran, Image de fond seule) |
Faible à moyen pour la fenêtre A (la boîte vide pourrait ne pas être reconnue : la marche resterait coupée, sans ligne C6-b) ; ne casse pas D10 (échec sûr : comme avant). |
| R4 | Texte lié par binding (TextDelegate) : GetText() évalue le binding, non vérifié |
Faible ; un binding vide donne « vide ». |
Aucun de ces cas ne crée un faux « marche libre » pour une boîte qui montre du texte ou un bouton ; le risque pour D10 est limité aux boîtes sans bouton ni texte (R1), estimé faible.
3.5 Compilabilité par lecture des en-têtes UE 5.8 (établi, D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\UMG)
| Élément | Source lue | Résultat |
|---|---|---|
UWidgetTree::ForEachWidget(TFunctionRef<void(UWidget*)>) const |
Public/Blueprint/WidgetTree.h l. 78 |
OK, appelable via const UUserWidget* ; la lambda (UWidget* Child) convient |
UWidget::IsVisible() const |
Public/Components/Widget.h l. 582 |
OK |
UWidget::GetRenderOpacity() const |
Widget.h l. 598 |
OK (aussi sur const UUserWidget*) |
UWidget::GetParent() const -> UPanelWidget* |
Widget.h l. 769 |
OK, Node = Node->GetParent() convertit UPanelWidget* en const UWidget* ; UPanelWidget est un UWidget, déclaré complet par l'include de UserWidget.h / WidgetTree.h (hypothèse : Components/PanelWidget.h est tiré par WidgetTree.h ; sinon C2036/C2440, voir point à confirmer au build) |
UTextBlock::GetText() const |
Components/TextBlock.h l. 95 |
OK |
URichTextBlock::GetText() const |
Components/RichTextBlock.h l. 196 |
OK |
UUserWidget::WidgetTree |
Blueprint/UserWidget.h l. 1524 TObjectPtr<UWidgetTree> WidgetTree; sous public: (l. 1521) |
OK, Widget->WidgetTree et ->ForEachWidget sur un const UUserWidget* : operator-> d'un TObjectPtr const rend UWidgetTree*, appelable |
Child->IsA<UButton>() |
Components/Button.h présent |
OK (UObject::IsA<T>() const) |
| Includes ajoutés | Blueprint/WidgetTree.h, Components/Button.h, Components/RichTextBlock.h, Components/TextBlock.h existent tous |
OK |
| Module UMG | Source\LifePlay\LifePlay.Build.cs l. 38 : { "Slate", "SlateCore", "UMG" } |
OK |
| Lambda récursive | ShowsContent est appelée dans la lambda de son propre corps : le nom est déjà déclaré (déclarateur vu) et la fonction est dans un espace de noms anonyme (l. 52), non capturée |
OK |
Argument par défaut int32 Depth = 0 |
l. 639, première déclaration, un seul appel avec 1 argument (l. 707) et un avec 2 (l. 660) | OK |
| Collisions de noms | Grep de `ShownUpToRoot |
ShowsContent |
Limite : lecture seule des en-têtes ; la compilation reste à faire (BUILD). const UWidget* appelant GetParent() : méthode const, OK.
3.6 Fins de ligne, ASCII, livrable IMPL (établi)
Commande Python -I (comptes d'octets) :
cpp : LF=1483 CRLF=1483 CR=1483
h : LF=90 CRLF=90 CR=90
IMPL.md : LF=86 CRLF=0 CR=0
- cpp et h : tous CRLF, zéro LF isolé, zéro CR isolé.
- Non-ASCII du cpp : 2 lignes (l. 454
« %s »et l. 513), même nombre dans l'instantané (2) et dansHEAD(1 ligne seule enHEAD: l. 513 absente ou ajoutée par un lot précédent, avant C6-b) ; le diff ne contient aucun non-ASCII ajouté (grep -P '^\+.*[^\x00-\x7F]'vide). Le correctif n'ajoute rien de non-ASCII : confirmé. STG-C6b-IMPL.md: LF pur (CRLF=0),C:\Users: 0 occurrence (grep -c), en-tête complet (Fiche, Niveau, Modèle prévu | utilisé, Agent, Skills).Tools\FileCheck.ps1appelé par pwsh avec arguments positionnels /-Files: paramètres rejetés (« Impossible de trouver un paramètre positionnel », « Split-Path … chaîne vide ») ; contrôle remplacé par le comptage d'octets ci-dessus (même objet).
4. Diff lu en entier
2 fichiers (LPDirectControlSubsystem.cpp, .h), 66 lignes ajoutées, 0 retirée, conforme à l'IMPL § 2. Régénéré et identique au fichier .diff.
5. Verdict
PASS-STATIC.
6. Points à confirmer par l'utilisateur
- Essai en jeu, fenêtre A rejouée : ligne
C6-b : boite Scene_C … sans contenu visiblepuis ZQSD marche (reporté, prochain build commun). - Essai D10 : boîte de scène visible, ZQSD sans effet,
M1e : marche coupee par le menu Scene_C, sans ligneC6-b(reporté). - Compilation
LifePlayEditor5.8 : 0 erreur (BUILD) ; vérifier en particulierUPanelWidgetcomplet pourGetParent()(voir 3.5).
Écarts
- IMPL hors gabarit : ses sections (Instantané, Changements, D10, Pas fait, Points à confirmer, MD5, Retour arrière, Fichiers à commiter) ne suivent pas l'ordre IMPL de
gabarits.md(1 Fichiers modifiés, 2 Écarts à la SPEC, 3 Instantané, 4 Pas fait, 5 Points à confirmer, 6 Fichiers à commiter) ; pas de section « Écarts à la SPEC » ni mention « Hors gabarit ». Mineur, sans effet sur le code. - IMPL § 4 : la ligne
WALK … menus=[…]deLPDebugSubsystemcompte toujoursScene_Csans filtre (annoncé par l'IMPL) : à garder en tête à la lecture des journaux. - Note sur le texte 3.6 : l'IMPL ne cite pas le non-ASCII existant du cpp (2 lignes, hérité).
Non rejoué
Compilation, LPTestStringCompat, ouverture de l'éditeur, essais en jeu (D10, fenêtre A), structure de /Game/UI/Scene.
Tours : 7 / 30