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.mdligne 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). Letarde 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-lulancé depuis le scratchpad ; le script refuse tout chemin hors destination (contrôle de traversée), puiszipfile.extractall. Code 0. Sortie : 12 entrées (__init__.py96 o,db.py9790,header_parser.py35560,ingest.py5047,server.py8860,unreal_paths.py7429,version.py7343,METADATA16127,WHEEL87,entry_points.txt109,LICENSE1067,RECORD1013). - 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
RECORDcorrespondent aux fichiers extraits (boucleopenssl dgst -sha256 -binary | base64, 11 « OK », 0 « DIFF »). Roue : 29 879 octets, MD524bd778673216792989cb0a6bf6bce94(relevé après extraction, roue inchangée). - Métadonnées :
METADATA:1-3Name unreal-api-mcp, Version 0.3.1 ;WHEELgénéré par hatchling 1.32.4 ;entry_points.txt:2-3unreal-api-ingest = unreal_api_mcp.ingest:main,unreal-api-mcp = unreal_api_mcp.server:main; dépendancesMETADATA:43-44mcp[cli]<2,>=1.8.0,python-dotenv>=1.0(non utilisé :grep dotenvsur les .py = 0 résultat) ; aucune occurrence desubprocess,eval(,exec(,pickle,os.system,__import__,ctypes,base64dans 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:executemanydans 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êmefqn. - Aucune table des surcharges ;
server.py:164-166renvoie 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 surMeshComponent.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\njuste avant la ligne N est exclu par la bornepos-1), puisrfind("\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). UneUE_DEPRECATEDsur 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) exigeUE_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 sansUCLASS|USTRUCT|UENUM|UFUNCTION|UPROPERTY|SLATE_BEGIN_ARGSrenvoie[].header_parser.py:900-918, 922-925: seules les classesUCLASS,USTRUCTet 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(FStringest dansUnrealString.h.inl).header_parser.py:651: les constructeurs (func_name == name) sont sautés.unreal_paths.py:121-132: seuls les dossiersClasses/etPublic/sont lus (pasPrivate/,Internal/).
D4 (nouveau), paramètres tronqués : ÉTABLI (mécanisme), signature obtenue estimée.
header_parser.py:91:_FUNC_DECLse 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_DEPRECATEDré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:129changerait ; la lecture du codeheader_parser.py:416-422ne laisse pas d'autre lecture plausible) ; la signature tronquée de PrintString ; le transport stdio par défaut de la bibliothèquemcp; 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 ceheader_parser.py. Ses défauts réels ne sont pas connus. Essai qui trancherait :ingestd'un moteur 5.8 puis requêtesget_function_signature("UMeshComponent::GetMaterialRelevance")etget_deprecation_warningssur 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-mcp0.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.inlet les dépréciations des constructeurs.
6. Points à confirmer par l'utilisateur
- Accepter le verdict NON ADOPTABLE et ne pas brancher
unreal-api-mcpdans.mcp.jsonni dans les copies. - Licence :
LICENSEest 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-validatele piège :tar -xfde Git Bash ne lit pas un zip (utiliserpython -I+zipfiledepuis le scratchpad, ou letarde Windows) ; vérifierRECORDpar sha256 avant lecture.
Tours : 17 / 30
Constats
- E1 (écart à la fiche, § 4a) :
tar -xfa échoué (message § 3.1). La fiche prévoit « arrêt si l'extraction échoue » mais propose aussi, dans la même rubrique, la méthodezipfile; 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:26annonce « 10 signatures comparées » ; la fiche demande 5 cas, 5 traités. - E3 :
__init__.py:3déclare__version__ = "0.1.1"alors que le paquet est en 0.3.1 ;python-dotenvest 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, brancheue5.8) ;whl-lu(hors dépôt) et le script du scratchpad ne se commitent pas.