LifePlay-Revival/Docs/Migration/etat/AG/P7/P7-T7-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

19 KiB

Fiche P7-T7 — Niveau N1 — Modèle prévu sonnet | utilisé Sonnet 5.5 (claude-sonnet-5-5) — Agent lp-validator — Skills sk-protocol, sk-recount, lp-validate (+ debug-verification)

P7-T7-VAL : lecture statique de codeturion/unreal-api-mcp 0.3.1 comme source de signatures UE 5.8 (2026-10-12)

Hors gabarit : aucun. Verdict de la fiche : NON ADOPTABLE. Verdict de validation : PASS-STATIC (tout est établi par lecture du code et des en-têtes ; rien n'a été exécuté, la part « estimé » est écrite en § 3.6).

Règle absolue tenue : la roue n'a pas été installée ni exécutée (aucun pip, uvx, venv ; aucun module du paquet importé ou lancé ; essais\P7-T7-codeturion.ps1 non lancé). Le seul interpréteur lancé est python -I sur un script d'extraction zipfile écrit dans le scratchpad (sous %TEMP%), lancé depuis le scratchpad, jamais depuis le dossier extrait.

1. Fiches amont relues

  • D:\Game\LifePlay-master 5.8\Docs\Migration\etat\AG\P7\fiches\P7-T7.md (fiche exécutée, relue en entier ; elle fait foi).
  • D:\Game\LifePlay-master 5.8\Docs\Migration\etat\AG\P7\P7-TACHES.md ligne 26 (registre : T7 « lancée », 10 signatures annoncées ; la fiche en demande 5, voir Écarts E2).
  • Gabarit : D:\Game\LifePlay-Sandbox\Tools\claude\skills\lp-doc\gabarits.md (section VAL).
  • Aucune IMPL ni BUILD amont : la fiche est un essai de lecture. Les autres livrables P7 (T1, T2, T3a, T4a, T9) ne sont pas des entrées de T7 et n'ont pas été relus.

2. Points à confirmer des IMPL

sans objet : aucune IMPL dans la chaîne de T7 (fiche sans « Dépend de », P7-TACHES.md:26). Les deux « points amont » de la rubrique 3 de la fiche, repris ici :

Point amont (fiche § 3) Verdict Preuve
D1 : les surcharges s'écrasent (clé fqn + INSERT OR REPLACE) PASS-STATIC : confirmé § 3.3 D1
D2 : une UE_DEPRECATED peut marquer la déclaration voisine PASS-STATIC : confirmé (et aggravé : fenêtre en lignes N-2..N pour les méthodes simples) § 3.3 D2

3. Critères rejoués

3.1 Extraction (fiche § 4a)

Trace : D:\Game\LifePlay_Backup_5.5\P7\whl-lu\ — Fiche P7-T7 — 2026-10-12, soirée

  • Commande 1 : mkdir whl-lu && tar -xf <roue> -C whl-lu (Git Bash). Obtenu, brut : tar: This does not look like a tar archive / tar: Skipping to next header / tar: Exiting with failure status due to previous errors (exit 2). Le tar de Git Bash (GNU) ne lit pas un zip ; aucun fichier créé (dossier resté vide).
  • Commande 2 (seconde méthode prescrite par la fiche § 4a, appliquée au lieu de l'arrêt, voir E1) : python -I p7t7_extract.py <roue> D:\Game\LifePlay_Backup_5.5\P7\whl-lu lancé depuis le scratchpad ; le script refuse tout chemin hors destination (contrôle de traversée), puis zipfile.extractall. Code 0. Sortie : 12 entrées (__init__.py 96 o, db.py 9790, header_parser.py 35560, ingest.py 5047, server.py 8860, unreal_paths.py 7429, version.py 7343, METADATA 16127, WHEEL 87, entry_points.txt 109, LICENSE 1067, RECORD 1013).
  • Recompte par une autre méthode : find whl-lu -type f = 12 fichiers ; find whl-lu -name '*.py' | xargs wc -l = 288 (db) + 1008 (header_parser) + 150 (ingest) + 290 (server) + 205 (unreal_paths) + 213 (version) + 3 (__init__) = 2157 lignes, égal au chiffre de la fiche (rubrique 3). Aucun __pycache__ (0), preuve qu'aucun module n'a été importé.
  • Intégrité : les 11 hachages sha256 de RECORD correspondent aux fichiers extraits (boucle openssl dgst -sha256 -binary | base64, 11 « OK », 0 « DIFF »). Roue : 29 879 octets, MD5 24bd778673216792989cb0a6bf6bce94 (relevé après extraction, roue inchangée).
  • Métadonnées : METADATA:1-3 Name unreal-api-mcp, Version 0.3.1 ; WHEEL généré par hatchling 1.32.4 ; entry_points.txt:2-3 unreal-api-ingest = unreal_api_mcp.ingest:main, unreal-api-mcp = unreal_api_mcp.server:main ; dépendances METADATA:43-44 mcp[cli]<2,>=1.8.0, python-dotenv>=1.0 (non utilisé : grep dotenv sur les .py = 0 résultat) ; aucune occurrence de subprocess, eval(, exec(, pickle, os.system, __import__, ctypes, base64 dans les 7 .py (grep, exit 1).

3.2 Relevé des accès réseau (fiche § 4b, critère § 8)

Commande : Grep http|urllib|requests|socket sur whl-lu\unreal_api_mcp. Sortie brute : 9 lignes, toutes dans version.py (8, 9, 15-16, 20, 87, 88, 122, 123, 184) ; aucune dans server.py, ingest.py, db.py, header_parser.py, unreal_paths.py.

Accès Source Quand Remarque
Téléchargement de unreal_docs_<version>.db depuis https://github.com/Codeturion/unreal-api-mcp/releases/download/db-v1 version.py:15-16, 85-94, 169-204 première ouverture de la base (premier appel d'outil, server.py:34) si aucun fichier local délai 60 s par opération ; écrit dans ~/.unreal-api-mcp/ (version.py:14, 170)
Requête HEAD de mise à jour, puis téléchargement et remplacement silencieux de la base locale si la taille distante diffère version.py:113-147 (appelée version.py:166) à chaque démarrage avec une base locale délai 3 s ; aucune somme de contrôle ni signature : le contenu de la base (résumés, indices de dépréciation) est servi à l'agent comme « vérité terrain » (server.py:21-24)
Aucun autre accès server.py (transport mcp.run() server.py:286, stdio par défaut de la bibliothèque mcp : estimé) ; ingest.py (hors réseau, lit le disque)

Variables lues : UNREAL_VERSION, UNREAL_PROJECT_PATH (version.py:32, 45), UNREAL_INSTALL_PATH, PROGRAMDATA (unreal_paths.py:16-18, 33). Version par défaut du code : 5.8 (version.py:18) ; le README annonce 5.7 (METADATA:96) : incohérence documentaire.

3.3 Les deux défauts (fiche § 3 et § 8)

D1, surcharges écrasées : ÉTABLI.

  • db.py:16-17 : fqn TEXT PRIMARY KEY ; db.py:94 : INSERT OR REPLACE INTO api_records ; db.py:124 : executemany dans l'ordre de la liste (le dernier gagne) ; ingest.py:123 : une seule insertion de tous les enregistrements.
  • La clé ne contient pas la signature : header_parser.py:559 (UFUNCTION : fqn = f"{owner}::{func_name}"), :599 (UPROPERTY), :705 (méthode simple : fqn = f"{name}::{func_name}"), :868 (Slate). Deux surcharges d'une même classe ont donc le même fqn.
  • Aucune table des surcharges ; server.py:164-166 renvoie l'unique ligne sans le dire. Exemple moteur réel : MeshComponent.h:128-129 (cas 1 ci-dessous).

D2, dépréciation sur la voisine : ÉTABLI, pour tous les types d'enregistrement.

  • Méthodes simples : _check_plain_deprecation (header_parser.py:409-426). Calcul tracé à la main sur MeshComponent.h:127-129 (e_k = fin de la ligne k) : before_start = source[:pos].rfind("\n", 0, pos-1) (l. 417) trouve e_(N-2) (le \n juste avant la ligne N est exclu par la borne pos-1), puis rfind("\n", 0, before_start) + 1 (l. 419) donne le début de la ligne N-2. La région (l. 422) couvre donc les lignes N-2 à N, soit la ligne située deux lignes au-dessus (le docstring l. 412-414 annonce « the two lines immediately above » sans en voir le piège). Une UE_DEPRECATED sur une déclaration d'une ligne marque aussi la déclaration d'après : cas typique « surcharge dépréciée suivie de son remplaçant ».
  • UFUNCTION / UPROPERTY / UCLASS / USTRUCT / UENUM : _check_deprecation (header_parser.py:392-406) regarde 300 caractères avant la macro (l. 394) et, selon l'appelant, 200 caractères après la déclaration pour UFUNCTION (l. 569) et 100 pour UPROPERTY (l. 603) : la déclaration précédente comme la suivante peuvent la marquer.
  • Les délégués sont toujours deprecated=0 (header_parser.py:763) ; les classes Slate aussi (:849) : une dépréciation de ces types est invisible.
  • Le motif _UE_DEPRECATED (header_parser.py:146-148) exige UE_DEPRECATED(<version>, "<message sans guillemet>") : tout autre formulaire n'est pas reconnu (estimé, non rencontré dans les 5 cas).

D3 (nouveau), trous de couverture : ÉTABLI.

  • header_parser.py:1002-1006 : un fichier sans UCLASS|USTRUCT|UENUM|UFUNCTION|UPROPERTY|SLATE_BEGIN_ARGS renvoie [].
  • header_parser.py:900-918, 922-925 : seules les classes UCLASS, USTRUCT et Slate sont des « régions » ; une classe C++ simple (IDetailLayoutBuilder, FString) n'est jamais propriétaire, et, dans un fichier qui a une macro, ses méthodes seraient attribuées à la dernière région précédente (estimé).
  • unreal_paths.py:174 : rglob("*.h") ne prend pas *.h.inl (FString est dans UnrealString.h.inl).
  • header_parser.py:651 : les constructeurs (func_name == name) sont sautés.
  • unreal_paths.py:121-132 : seuls les dossiers Classes/ et Public/ sont lus (pas Private/, Internal/).

D4 (nouveau), paramètres tronqués : ÉTABLI (mécanisme), signature obtenue estimée.

  • header_parser.py:91 : _FUNC_DECL se termine par \(([^)]*)\), non équilibré, pour les UFUNCTION. Tout paramètre par défaut contenant une parenthèse (FString("Hello"), FLinearColor(...), FVector(...)) coupe la liste au premier ). Les méthodes simples, elles, utilisent l'extraction équilibrée (header_parser.py:295-321, 689) : traitement inégal.

3.4 Tableau des 5 cas (fiche § 4c, critère § 8)

Déclarations réelles relues dans D:\Game\Launcher\Engine\UE_5.8\Engine\Source\... (lecture seule ; chemins relatifs à cette racine).

fqn Réel (fichier:ligne moteur) Base prédite (ligne de code qui fonde) Écart
UMeshComponent::GetMaterialRelevance Runtime\Engine\Classes\Components\MeshComponent.h:127 UE_DEPRECATED(5.7, ...), :128 surcharge ERHIFeatureLevel::Type (dépréciée), :129 surcharge EShaderPlatform (valide). Classe : UCLASS :23-24, seule du fichier (Grep) Une seule ligne, celle de :129 (même fqn header_parser.py:705, clé db.py:17, le dernier gagne db.py:94, 124) : params InShaderPlatform:EShaderPlatform, retour FMaterialRelevance, spécificateur virtual. Drapeau : deprecated=1 avec le message de :127, car la région de :129 va de :127 à :129 (header_parser.py:417-422, calcul § 3.3 D2). Résumé vide (header_parser.py:226-229, 233-239 : la ligne :127 s'intercale entre le commentaire et la déclaration) D1 + D2 : la surcharge dépréciée (ERHIFeatureLevel) disparaît ; la surcharge valide, celle qu'il faut employer, est affichée « DEPRECATED : Please use GetMaterialRelevance with EShaderPlatform argument... » (inversion, server.py:111-116)
IDetailLayoutBuilder::GetDetailsView Editor\PropertyEditor\Public\DetailLayoutBuilder.h:63-67 (const, UE_DEPRECATED(5.5)) et :74-78 (non const, UE_DEPRECATED(5.5)) ; remplaçantes :61 et :72 (GetDetailsViewSharedPtr). Classe C++ simple :35 Aucune ligne : le fichier ne contient aucune macro de réflexion (Grep, 0 occurrence) donc parse_header_file renvoie [] (header_parser.py:1002-1006) ; la classe n'est de toute façon pas une région (:900-918). get_deprecation_warnings("GetDetailsView") répond « n'est pas déprécié (ou introuvable) » (server.py:275), ou renvoie d'autres lignes via le repli FTS (db.py:281-288) D3 : dépréciation 5.5 invisible (faux négatif présenté comme « pas déprécié »)
FSlateFontInfo::FSlateFontInfo Runtime\SlateCore\Public\Fonts\SlateFontInfo.h:245-246, :255-256, :265-266, :275-276 : quatre constructeurs UE_DEPRECATED(5.6, "Use constructor with FCompositeFont instead.") ; non dépréciés :227, :236 (+ défaut :215). USTRUCT :145, struct FSlateFontInfo :146 Aucune ligne de constructeur : func_name == name → continue (header_parser.py:651). Le type est indexé (USTRUCT, header_parser.py:478-503) avec deprecated=0 (les 300 caractères avant :145, soit :129-144, ne contiennent pas de UE_DEPRECATED). Seul FSlateFontInfo::FontName_DEPRECATED (:205) est marqué (suffixe, header_parser.py:605) D3 : les quatre constructeurs dépréciés en 5.6 sont invisibles ; aucun constructeur n'est jamais consultable
FString::ParseIntoArray Runtime\Core\Public\Containers\UnrealString.h.inl:1746 (const ElementType* pchDelim) et :1783 (DelimArray, NumDelims) ; voisines ParseIntoArrayWS :1759, ParseIntoArrayLines :1770. Aucune dépréciation Aucune ligne : *.h.inl non collecté (unreal_paths.py:174) ; UnrealString.h sans macro (Grep, 0) donc [] (header_parser.py:1002-1006) ; FString non réfléchie (:900-918). get_function_signature : exact vide, préfixe vide, puis repli FTS « Similar functions » (server.py:164-184) D3 : API de chaînes centrale absente ; D1 aurait écrasé :1746/:1783 s'ils avaient été lus
UKismetSystemLibrary::PrintString (témoin) Runtime\Engine\Classes\Kismet\KismetSystemLibrary.h:565-566 (UFUNCTION + static ENGINE_API void PrintString(...), 7 paramètres), classe UCLASS :101-102 ; aucune UE_DEPRECATED en :540-589 Une ligne, fqn exact (header_parser.py:559), deprecated=0 (rien dans les 300 car. avant ni les 200 après, :394, 569), inclusion Kismet/KismetSystemLibrary.h. Mais \(([^)]*)\) (header_parser.py:91) s'arrête au premier ) de FString("Hello") (:566) : 2 paramètres sur 7 (WorldContextObject, InString) ; bPrintToScreen, bPrintToLog, TextColor, Duration, Key perdus (header_parser.py:566-567) ; retour void D4 : le témoin « simple » est faux (signature partielle sans avertissement) ; D1/D2 n'y touchent pas

3.5 Verdict selon le critère de la fiche (rubrique 8)

Règle : ADOPTABLE si aucun défaut ne touche les surcharges ni le drapeau déprécié, sinon NON ADOPTABLE avec le compte des cas touchés.

  • NON ADOPTABLE. Cas touchés : 5 sur 5 (1 par D1+D2, 3 par D3, 1 par D4).
  • Cas portant une UE_DEPRECATED réelle dans les en-têtes 5.8 (cas 1, 2, 3) : 3 sur 3 faussés (1 inversé : la surcharge valide donnée pour dépréciée ; 2 absents : dépréciation invisible). C'est la promesse centrale du paquet (METADATA:61, 150 : « dépréciations »).
  • Cas intact quant au drapeau : 1 (PrintString), mais signature tronquée.

3.6 Établi / estimé / incertain (sk-protocol § 1)

  • Établi (code et en-têtes lus, citations ci-dessus) : le mécanisme de D1, D2, D3, D4 ; les déclarations réelles des 5 cas ; les accès réseau ; l'intégrité de la roue (RECORD) ; le décompte des lignes.
  • Estimé (déduit du code, non exécuté) : le contenu exact des enregistrements prédits au tableau 3.4 (calcul d'indices tracé à la main : si une borne rfind était décalée d'un caractère, D2 sur la ligne :129 changerait ; la lecture du code header_parser.py:416-422 ne laisse pas d'autre lecture plausible) ; la signature tronquée de PrintString ; le transport stdio par défaut de la bibliothèque mcp ; l'attribution à la mauvaise classe pour les classes non réfléchies.
  • Incertain : la base prébâtie téléchargée (db-v1) est construite par une CI (METADATA:63, 120) dont le code n'est pas dans la roue ; rien ne prouve qu'elle utilise ce header_parser.py. Ses défauts réels ne sont pas connus. Essai qui trancherait : ingest d'un moteur 5.8 puis requêtes get_function_signature("UMeshComponent::GetMaterialRelevance") et get_deprecation_warnings sur une base jetable, dans une machine ou un venv isolés, interdit par la fiche (décision de l'utilisateur, § 6).

4. Diff lu en entier

sans objet : aucune modification d'un fichier suivi par git. git status --short -- Docs/Migration/etat/AG/P7 : ?? Docs/Migration/etat/AG/P7/ (dossier P7 entier non suivi, le livrable s'y ajoute). Inventaire de ce qui a été écrit :

  • D:\Game\LifePlay_Backup_5.5\P7\whl-lu\ (dossier neuf, hors dépôt) : 12 fichiers, 3 dossiers (unreal_api_mcp, unreal_api_mcp-0.3.1.dist-info, licenses).
  • %TEMP%\claude\D--Game-LifePlay-master-5-8\f3df474e-f4bb-46ba-a76c-69f3498593ce\scratchpad\p7t7_extract.py (script d'extraction, sous %TEMP%).
  • Ce livrable.
  • Moteur D:\Game\Launcher\Engine\UE_5.8 : lu seulement (Read, Grep). Copies du jeu, .mcp.json : non touchés.

5. Verdict

  • Fiche P7-T7 : NON ADOPTABLE (codeturion/unreal-api-mcp 0.3.1 ne doit pas servir de source de signatures UE 5.8 à lp-impl ni lp-cart tel quel). Cinq cas sur cinq touchés ; les trois dépréciations réelles sont perdues ou inversées ; les surcharges s'écrasent.
  • Validation : PASS-STATIC (critères de la fiche remplis par lecture : deux défauts établis par citation, tableau de 5 lignes, relevé réseau, part estimée écrite ; rien d'exécuté).
  • La méthode actuelle du projet (Read et Grep de l'en-tête moteur, fichier:ligne) reste la référence ; elle est la seule à voir les surcharges, les .h.inl et les dépréciations des constructeurs.

6. Points à confirmer par l'utilisateur

  • Accepter le verdict NON ADOPTABLE et ne pas brancher unreal-api-mcp dans .mcp.json ni dans les copies.
  • Licence : LICENSE est MIT (LICENSE:1-21) mais le README du paquet ajoute « Free to use ... for any personal or non-commercial purpose. Commercial use requires permission. » (METADATA:321-323) ; contradiction non tranchée (sans objet si le paquet n'est pas adopté).
  • Faut-il convertir la part « estimé » en « établi » par un essai d'exécution (ingest sur une base jetable) ? Non nécessaire pour le verdict ; décision de l'utilisateur, hors cette fiche.
  • Verser en lp-validate le piège : tar -xf de Git Bash ne lit pas un zip (utiliser python -I + zipfile depuis le scratchpad, ou le tar de Windows) ; vérifier RECORD par sha256 avant lecture.

Tours : 17 / 30

Constats

  • E1 (écart à la fiche, § 4a) : tar -xf a échoué (message § 3.1). La fiche prévoit « arrêt si l'extraction échoue » mais propose aussi, dans la même rubrique, la méthode zipfile ; j'ai pris la seconde sans autre changement de périmètre (dossier de destination, interdits identiques). Si l'orchestrateur lit la règle d'arrêt strictement, c'est un écart à arbitrer.
  • E2 (registre) : P7-TACHES.md:26 annonce « 10 signatures comparées » ; la fiche demande 5 cas, 5 traités.
  • E3 : __init__.py:3 déclare __version__ = "0.1.1" alors que le paquet est en 0.3.1 ; python-dotenv est déclaré (METADATA:44) mais jamais importé ; Provides-Extra: ingest (METADATA:45) sans dépendance associée. Signes d'un paquet Alpha (METADATA:32).
  • Risque de chaîne d'approvisionnement : la base est un fichier SQLite téléchargé sans somme de contrôle (version.py:113-147) et ses textes (résumés) sont servis à l'agent comme instructions de confiance (server.py:18-25) : vecteur d'injection de contenu, en plus des défauts d'exactitude.
  • Fichiers à commiter : A Docs/Migration/etat/AG/P7/P7-T7-VAL.md (dépôt jeu 5.8, branche ue5.8) ; whl-lu (hors dépôt) et le script du scratchpad ne se commitent pas.