LifePlay-Revival/Docs/Migration/etat/ST/STE/STE-H3g-IMPL.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

159 lines
19 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 STE-H3g-I — Niveau N3 — Modèle prévu opus (xhigh) | utilisé claude-opus-5-5 — Agent lp-mcp-bp — Skills sk-protocol, sk-change-safety, lp-mcp, lp-lot
# STE-H3g-IMPL : garde G16 (`GI:EventGraph`, `UpdateDefaultHair`) écrite par MCP (2026-10-13)
Copie `D:\Game\LifePlay-master 5.8`, branche `ue5.8`, HEAD `0745917`. SPEC : `STE-H3g-SPEC.md` § 2.0, 2.1, 2.3, 3, 4, 7 (G16 seule ; G15 non écrite, décision Q-H3g-1 = c).
UE-GO de Big Boss reçu (fiche, rubrique 3). Éditeur headless lancé et fermé par l'agent (lp-mcp § 2). Un appel MCP par message, outils Epic seulement (aucun `hyper_*`, aucun `execute_tool_script`).
## 1. Fichiers modifiés
Un seul : `Content\BPs\GI.uasset`, graphe `/Game/BPs/GI.GI:EventGraph`, enregistré par `save_assets {asset_paths:["/Game/BPs/GI"]}` → `true`.
**Empreintes** (Git Bash, copie 5.8, `md5sum Content/BPs/GI.uasset Content/BPs/Person.uasset Content/BPs/Room.uasset "/d/Game/LifePlay_Backup_5.5/STE-H3g/Content/BPs/GI.uasset"`) :
| Fichier | Avant (17:53) | Après (18:07, éditeur fermé) |
|---|---|---|
| `Content/BPs/GI.uasset` | `c4817b847ecf246c859647577647d6e9` | **`0e6aedcccd1a6522282f9a423843ce45`** |
| instantané `D:\Game\LifePlay_Backup_5.5\STE-H3g\Content\BPs\GI.uasset` | `c4817b847ecf246c859647577647d6e9` | `c4817b847ecf246c859647577647d6e9` (inchangé) |
| `Content/BPs/Person.uasset` (autre lot, non ouvert) | `8668a47c627f7a5254910cf0ac33b12a` | `8668a47c627f7a5254910cf0ac33b12a` |
| `Content/BPs/Room.uasset` (autre lot, non ouvert) | `ca2a9a0baaca4130fd5c318797f008ae` | `ca2a9a0baaca4130fd5c318797f008ae` |
`git status --short -- Content` : avant ` M Person`, ` M Room` ; après ` M Content/BPs/GI.uasset`, ` M Content/BPs/Person.uasset`, ` M Content/BPs/Room.uasset`.
**Comptes de `GI:EventGraph`** (`find_nodes {graph:{refPath:"/Game/BPs/GI.GI:EventGraph"}, title:""}`, sortie enregistrée par le client puis comptée par `grep -o 'GI\.GI:EventGraph\.K2Node_[A-Za-z]*_[0-9]*'`) :
**6 247 → 6 251** nœuds `K2Node` (+4, exactement les 4 nouveaux) ; avec les 2 commentaires (`EdGraphNode_Comment_0`, `_1`) que `find_nodes` ne liste pas : **6 249 → 6 253**, compte du dump. Voir § 2 E1.
### 1.1 P4 : nœuds existants relus avant écriture (`get_node_infos`, deux appels de 8 nœuds)
Préfixe des `refPath` : `/Game/BPs/GI.GI:EventGraph.K2Node_`. Les 16 nœuds de la SPEC § 2.0 P4 retrouvés, **tous conformes** à la colonne « Avant » (§ 2.3.1).
| Nœud | type_id relu, position | Liens et indices relevés |
|---|---|---|
| `CustomEvent_5` | `AddEvent|Custom|UpdateDefaultHair`, (-10432, 9584) | out `then` 1 → `IfThenElse_104` (0) |
| `IfThenElse_104` | `Utilitaires|ContrôleDeFlux|Branche`, (-9872, 9600) | in `execute` 0 ← `CallFunction_250`, `CustomEvent_5` ; `Condition` 1 ← `VariableGet_3775` ; `then` 0 → `IfThenElse_65`, `else` 1 → `IfThenElse_66` |
| `IfThenElse_65` / `_66` | Branche, (-9648, 9504) / (-9712, 9744) | `Condition` ← `CallFunction_235` ; `then` 0 → `CallFunction_662` / `_661` ; `else` 1 → `CallFunction_259` / `_287` |
| `CallFunction_259` / `_287` | `|LoadHairMeshIfNeeded` | `then` 0 → `CallFunction_662` / `_661` (in 0) |
| `CallFunction_662` / `_661` | `Composants|Maillagesurfacé|SetSkinnedAssetAndUpdate`, (-9216, 9472) / (-9184, 9696) | in `execute` 0 ← `_259` + `IfThenElse_65` / `_287` + `IfThenElse_66` ; `self` 1 ← `VariableGet_241` ; `NewMesh` 2 ← `BreakStruct_12` / `_13` (0) ; `bReinitPose` 3 = `true` ; **out `then` 0 → `MacroInstance_5` / `_4` (in 0), seul lien** |
| `MacroInstance_5` / `_4` | `Utilities|Array|ForEachLoop`, (-8928, 9520) / (-8656, 9712) | in `Exec` 0 ← `CallFunction_662` / `_661` seul ; `Array` 1 ← `VariableGet_1147` / `_64` ; out `LoopBody` 0 → `CallFunction_2918` / `_2917` ; `Array Element` 1 → `BreakStruct_101` / `_100` ; `Array Index` 2 → `CallFunction_2918` / `_2917` (in 2) ; **`Completed` 3 → `CallFunction_5654` (in 0), seul lien** |
| `CallFunction_5654` | `|TurnMaterialDynamic`, (-8176, 9552) | in `execute` 0 ← `MacroInstance_4` (3), `MacroInstance_5` (3) ; `Mesh` 2 ← `VariableGet_241` ; `then` 0 → `CallFunction_237` |
| `CallFunction_237` | `|FitMorphableHair`, (-7856, 9648) | in `execute` 0 ← `CallFunction_5654` ; `self` ← `VariableGet_2404` ; `then` sans lien |
| `BreakStruct_12` / `_13` | `Utilitaires|Structure|BreakSMBool`, (-9344, 9232) / (-9216, 9872) | in `SMBool` ← `GetArrayItem_4` / `_6` ; **out `SkeletalMesh_2_93573D9945CD4136090CCBA1F1188DAC` = 0** → `VariableGet_1147` / `_64` (in 0) + `CallFunction_662` / `_661` (in 2) ; sorties 1-7 sans lien |
| `VariableGet_1147` / `_64` | `|GetMaterials`, (-9312, 9440) / (-8976, 9904) | in `self` 0 ← `BreakStruct_12` / `_13` (0) ; out `Materials` 0 → `MacroInstance_5` / `_4` (in 1) |
### 1.2 Nœuds créés (correspondance SPEC → nom réel → type_id)
Chaque `type_id` vérifié par `find_node_types {graph, type_id_filter, context_pins:[]}` juste avant son `create_node` (4 appels), nœuds relus par `get_node_infos` avant tout câblage.
| SPEC | Nœud réel (`refPath` `/Game/BPs/GI.GI:EventGraph.K2Node_…`) | Filtre → réponse | type_id de création = relu | Broches (index) | Position |
|---|---|---|---|---|---|
| G16a-V IsValid | `CallFunction_715` | `Utilitaires|IsValid` → 5 : `…IsValidSoftObjectReference`, `…IsValidSoftClassReference`, `…IsValidInterface`, `…IsValidClass`, `Utilitaires|IsValid` | `Utilitaires|IsValid` | pur ; in `Object` 0 ; out `ReturnValue` 0 | -9072, 9296 |
| G16a-B Branche | `IfThenElse_219` | `ContrôleDeFlux|Branche` → 1 : `Utilitaires|ContrôleDeFlux|Branche` | `Utilitaires|ContrôleDeFlux|Branche` | in `execute` 0, `Condition` 1 (= `true` par défaut) ; out `then` 0, `else` 1 | -8944, 9376 |
| G16b-V IsValid | `CallFunction_720` | idem G16a-V (5) | `Utilitaires|IsValid` | idem | -8960, 9600 |
| G16b-B Branche | `IfThenElse_220` | idem G16a-B (1) | `Utilitaires|ContrôleDeFlux|Branche` | idem | -8864, 9712 |
Aucun `set_pin_value`, aucun `delete_node`.
### 1.3 Coupures et liens (un appel MCP par message, réponse `null` pour chacun)
| # | Geste | Sortie (index) | Entrée (index) |
|---|---|---|---|
| C1 | `break_pins` | `CallFunction_662.then` (0) | `MacroInstance_5.Exec` (0) |
| 1 | `connect_pins` | `BreakStruct_12.SkeletalMesh_2_93573D9945CD4136090CCBA1F1188DAC` (0) | `CallFunction_715.Object` (0) |
| 2 | `connect_pins` | `CallFunction_662.then` (0) | `IfThenElse_219.execute` (0) |
| 3 | `connect_pins` | `CallFunction_715.ReturnValue` (0) | `IfThenElse_219.Condition` (1) |
| 4 | `connect_pins` | `IfThenElse_219.then` (0) | `MacroInstance_5.Exec` (0) |
| 5 | `connect_pins` | `IfThenElse_219.else` (1) | `CallFunction_5654.execute` (0) |
| C2 | `break_pins` | `CallFunction_661.then` (0) | `MacroInstance_4.Exec` (0) |
| 6 | `connect_pins` | `BreakStruct_13.SkeletalMesh_2_93573D9945CD4136090CCBA1F1188DAC` (0) | `CallFunction_720.Object` (0) |
| 7 | `connect_pins` | `CallFunction_661.then` (0) | `IfThenElse_220.execute` (0) |
| 8 | `connect_pins` | `CallFunction_720.ReturnValue` (0) | `IfThenElse_220.Condition` (1) |
| 9 | `connect_pins` | `IfThenElse_220.then` (0) | `MacroInstance_4.Exec` (0) |
| 10 | `connect_pins` | `IfThenElse_220.else` (1) | `CallFunction_5654.execute` (0) |
**Relecture** (`get_node_infos` de 20 nœuds en deux appels : les 4 nouveaux + les 16 de P4 + `CallFunction_2917` / `_2918`), conforme au § 2.3.2 :
- `CallFunction_662.then` → `IfThenElse_219.execute` **seul** ; `MacroInstance_5.Exec` ← `IfThenElse_219.then` **seul** ; idem `CallFunction_661.then` → `IfThenElse_220` seul, `MacroInstance_4.Exec` ← `IfThenElse_220.then` seul.
- `IfThenElse_219` : `Condition` ← `CallFunction_715.ReturnValue` ; `else` → `CallFunction_5654.execute`. `IfThenElse_220` : `Condition` ← `CallFunction_720.ReturnValue` ; `else` → `CallFunction_5654.execute`.
- `CallFunction_715.Object` ← `BreakStruct_12` (0) ; `CallFunction_720.Object` ← `BreakStruct_13` (0).
- `BreakStruct_12.SkeletalMesh_2_…` → `VariableGet_1147` (0), `CallFunction_662.NewMesh` (2), `CallFunction_715.Object` (0) ; `BreakStruct_13.SkeletalMesh_2_…` → `VariableGet_64`, `CallFunction_661.NewMesh`, `CallFunction_720.Object`.
- `CallFunction_5654.execute` : **4 sources** : `MacroInstance_4` (3), `MacroInstance_5` (3), `IfThenElse_219` (1), `IfThenElse_220` (1).
- Inchangés : `SetSkinnedAssetAndUpdate` ×2 (`execute`, `self`, `NewMesh`, `bReinitPose = true`), `MacroInstance_4/_5` (`Array`, `LoopBody`, `Array Element`, `Array Index`, `Completed`), `VariableGet_1147/_64`, `CallFunction_5654.then` → `CallFunction_237`, `CustomEvent_5`, `IfThenElse_104/_65/_66`, `CallFunction_259/_287`, `CallFunction_2917/_2918`.
### 1.4 Compilation et enregistrement
Journal : `D:\Game\LifePlay-master 5.8\Saved\Logs\STE-H3g-headless-20261013-175345.log` (heures UTC = locale − 2 h).
- `compile_blueprint {blueprint:{refPath:"/Game/BPs/GI.GI"}, warnings_as_errors:true}` → `null`. Journal l. 2332, `16.06.47:036` : `LogBlueprint: Compiling Blueprint '/Game/BPs/GI.GI'` ; l. 2333 `16.06.51:737` : `LogUObjectHash: Compacting …`.
`tail -n +2330 <journal> | grep -c -E 'Error|Warning'` → `0`. `hyper_blueprint_debug_inspect` non utilisé (absent du serveur, H3dI:156 ; fiche).
- `save_assets {asset_paths:["/Game/BPs/GI"]}` (`editor_toolset.toolsets.asset.AssetTools`) → `true`. Journal l. 2340, `16.07.00:306` : `Cmd: OBJ SAVEPACKAGE PACKAGE="/Game/BPs/GI" FILE="…/Content/BPs/GI.uasset" SILENT=true` ;
`16.07.04:595` : déplacement du `.tmp` vers `Content/BPs/GI.uasset` ; `AssetCheck: /Game/BPs/GI` (1 ressource validée), sans échec listé. `grep -n SAVEPACKAGE <journal>` → 2 lignes : 2274 (autosave, § 2 E4) et 2340 (seul enregistrement dans `Content`).
- Éditeur : lancé 17:54:02 (PID 36020), `Stop-Process -Id 36020` à 18:07:12 ; `Tools\UeState.ps1` à 18:07:24 → `processus=0 editeur=0 compilation=0 shaders=0 jeu=0` (code 0).
### 1.5 Garde `Accessed None` (lp-mcp § 1 règle 4) et comportement
- `IsValid` justifié : « maillage vide » est un **état normal** ici : l'entrée de `HairstyleTable` lue par `GetArrayItem_4/_6` peut rendre `SkeletalMesh_2 = None` (observé 2 fois dans HJ:16058, 16086), et l'utilisateur a décidé de garder « pas de coiffure, comme aujourd'hui » (décision Q1, SPEC § 1).
- Cascade de Branche seule, aucun AND / OR / Select. `SetSkinnedAssetAndUpdate(HairSM, None)` reste appelé avant la garde (la coiffure est toujours vidée).
- Maillage valide : `then` → boucle, chemin d'origine (établi par construction). Maillage None : `else` → `CallFunction_5654` → `CallFunction_237`, sans lecture `Materials` (estimé identique à l'exécution actuelle, voir R-H3g-4 ci-dessous).
### 1.6 Réponse au point amont R-H3g-4 (successeurs des boucles)
**Établi** (relecture `get_node_infos` du jour) : `MacroInstance_5` et `_4` n'ont, en exécution, que deux sorties reliées : `LoopBody` (0) → `CallFunction_2918` / `_2917` (`Rendu|Matériau|SetMaterial`, dont la sortie `then` (0) **n'a aucun lien**) et `Completed` (3) → `CallFunction_5654.execute` **seul**. Aucun autre successeur que `CallFunction_5654` après la boucle ; le corps de boucle s'arrête à `SetMaterial`.
Donc l'`else` des gardes (→ `CallFunction_5654`) reproduit la suite d'exécution actuelle dès que la boucle fait 0 itération. Le « 0 itération sur tableau effacé » reste **estimé** (macro `ForEachLoop` non lue, SPEC § 6) ; s'il était faux, la seule différence serait des `SetMaterial` sur `HairSM` sans maillage.
## 2. Écarts à la SPEC
- **E1 (compte)** : `find_nodes title:""` rend **6 247** nœuds avant écriture, pas 6 249. Les 2 manquants sont les commentaires du graphe, que `find_nodes` ne liste pas : le dump compte `EdGraphNode_Comment_0` et `_1` (GEV, premier listing : 6 249 noms dont 6 247 `K2Node_*`) ;
`diff` des noms `K2Node_*` du dump et de la liste MCP → aucune différence (code 0) ; `get_node_infos` sur les deux commentaires → `'EdGraphNode_Comment' object has no attribute 'get_node_title'` (objets résolus, non K2). Le graphe est donc celui du dump (MD5 identique en plus). J'ai poursuivi : l'écart est dans la méthode de comptage, pas dans l'état.
Après : 6 251 par `find_nodes` = **6 253** au sens du dump (à confirmer par le dump de VAL, § 5).
- **E2 (attente MCP)** : `Wait-HyperAIStudioMCP.ps1 -Port 8000 -UrlPath /mcp -TimeoutSeconds 540` → code 1, sans sortie, après 540 s (17:54 → 18:03), alors que le serveur écoutait depuis `15.54.14:094` UTC (journal l. 1903-1906 : `Starting MCP server on port 8000`, `Created new HttpListener on 127.0.0.1:8000` ; `Get-NetTCPConnection -LocalPort 8000` → propriétaire 36020) ; `get_current_level` a répondu `/Game/Scenes/CentralLondon`. Cause du code 1 non instruite.
- **E3 (lecture hors liste)** : un `get_node_infos` sur les deux commentaires (E1) a laissé `LogScript: Warning: 'EdGraphNode_Comment' object has no attribute 'get_node_title'` au journal (16.04.18, avant la compilation) ; lecture seule.
- **E4 (autosave)** : l'éditeur a écrit `Saved\Autosaves\Game\BPs\GI_Auto1.uasset` à `16.05.07` UTC (l. 2274, pendant le câblage). Déplacé (pas supprimé) vers `D:\Game\LifePlay_Backup_5.5\STE-H3g\autosave\GI_Auto1.uasset` (52 611 967 octets, MD5 `4740351cdf4d3733f990922f87367723`) ; plus aucun `GI_Auto*` sous `Saved\Autosaves`. Les autres autosaves (`Person_Auto1`, `Room_Auto1-4`, `TestStatic_Auto1`, `UI\MainMenu_Auto1`) préexistaient et n'ont pas été touchés.
- **E5 (P5)** : `get_node_infos` des nouveaux nœuds fait par paire (après les deux créations de chaque garde), avant tout câblage, au lieu d'un appel après chaque création.
- **E6 (budget)** : 53 tours pour un budget ≈ 50 (plafond 60).
- Aucun autre : 4 nœuds, 2 coupures, 10 liens exactement selon § 2.3.2 ; G15 non écrite ; aucun autre graphe ni asset ouvert en écriture ; Person et Room ni chargés ni enregistrés.
## 3. Instantané
Pris par l'orchestrateur avant la fiche (pas de `Snapshot.ps1` relancé) : `D:\Game\LifePlay_Backup_5.5\STE-H3g\Content\BPs\GI.uasset`, MD5 `c4817b847ecf246c859647577647d6e9` = GI de départ, relu identique après l'enregistrement. Manifeste `D:\Game\LifePlay_Backup_5.5\STE-H3g\manifest.csv` non relu par l'agent.
Retour arrière (proposé, non lancé ; décision de l'orchestrateur, éditeur fermé) : `.\Tools\Restore.ps1 -Lot STE-H3g -Only Content\BPs\GI.uasset -WhatIf`, puis sans `-WhatIf` ; MD5 attendu `c4817b847ecf246c859647577647d6e9`. Après commit : `git revert` du commit du ticket STE-H3g.
Entrée de journal (sk-change-safety) : `2026-10-13 | G16 (2 IsValid + 2 Branche) dans GI:EventGraph | Content/BPs/GI.uasset | retour arrière : Restore.ps1 -Lot STE-H3g -Only Content\BPs\GI.uasset | instantané : D:\Game\LifePlay_Backup_5.5\STE-H3g\ | vérification : 6 247 → 6 251 K2Node (+4), relecture conforme, compilation 0 / 0, MD5 0e6aedcc…`
## 4. Ce qui n'a pas été fait
- G15 (`isSameAs`) : non écrite (décision Q-H3g-1 = c) ; `isSameAs` non chargé en lecture ni en écriture.
- Dumps `LPDumpFunction` après IMPL, `CompileAllBlueprints`, `LPTestStringCompat`, build et journal de jeu : à la VAL / au BUILD (SPEC § 7).
- Cause du maillage None (piste `Daz`) : hors périmètre (SPEC § 2.3.3, R-H3g-7).
- Gel annoncé aux autres sessions et `BUILD-FIN` : à l'orchestrateur.
## 5. Points à confirmer en VAL
- Dump `-BP=GI -Fn=EventGraph -Pins -Exec` → `(6253 noeuds)` ; liens du § 7.1 de la SPEC avec les noms réels : G16a-V = `CallFunction_715`, G16a-B = `IfThenElse_219`, G16b-V = `CallFunction_720`, G16b-B = `IfThenElse_220`.
- `DiffRemplacementNoeuds.py` sur EventGraph (avant = `dumps\GI__EventGraph_P2.txt`) : seuls ces 4 nœuds, 2 coupures, 10 liens.
- **`isSameAs` reste à 11 nœuds** (G15 abandonnée : le « 15 » de la SPEC § 7.1 ne s'applique plus) ; `GetVariable` 53, `Action:EventGraph` 363, `CallFunctionReturnBool` 594 inchangés.
- `CompileAllBlueprints` éditeur fermé : BP `/Game/` 0 erreur ; `LPTestStringCompat` 3120 / 0 / 60.
- MD5 de GI = `0e6aedcccd1a6522282f9a423843ce45` au départ de la VAL ; Person `8668a47c…` et Room `ca2a9a0b…` inchangés.
- Journal de jeu (build, même ligne de commande que HJ) : `SkeletalMesh_2_93573D` 2 → 0, `UpdateDefaultHair` 4 → 0 ; `Person_24_.*of length 0` (2) et `isSameAs` (3) **attendus inchangés** (G15 non écrite) ; preuve de parcours rejoué de la SPEC § 7.4 (G16).
- R-H3g-4 : 0 itération sur tableau effacé reste estimé (§ 1.6) ; aucune autre suite d'exécution que `CallFunction_5654` (établi).
- Code 1 de `Wait-HyperAIStudioMCP.ps1` alors que le serveur répondait (E2) : à instruire hors lot.
## 6. Fichiers à commiter
Dépôt jeu, branche `ue5.8`, ticket au gardien :
- M `Content/BPs/GI.uasset`
- A `Docs/Migration/etat/ST/STE/STE-H3g-IMPL.md`
Ne pas inclure `Content/BPs/Person.uasset` ni `Content/BPs/Room.uasset` (autres lots, ` M` préexistants).
Tours : 53 / 50 (plafond 60)
## Constats
Commandes et sorties brutes (extraits) :
- Entrée : `md5sum Content/BPs/GI.uasset Content/BPs/Person.uasset Content/BPs/Room.uasset <instantané GI>` → `c4817b847ecf246c859647577647d6e9`, `8668a47c627f7a5254910cf0ac33b12a`, `ca2a9a0baaca4130fd5c318797f008ae`, `c4817b847ecf246c859647577647d6e9` ; `git rev-parse --short HEAD` → `0745917` ; `Tools/UeState.ps1` → `processus=0 editeur=0 compilation=0 shaders=0 jeu=0`.
- Lancement : `Start-Process UnrealEditor.exe "<copie>\LifePlay.uproject" -RenderOffScreen -unattended -nosplash -NoSound -ModelContextProtocolStartServer -ModelContextProtocolPort=8000 "-abslog=<copie>\Saved\Logs\STE-H3g-headless-20261013-175345.log"` → `PID=36020`, `17:54:02`. Aucune demande de recompilation de modules : `grep -i -E "modules are missing|rebuild|out of date|built with a different"` → aucune ligne utile (le seul « Took … seconds » relevé concerne la configuration).
- Comptes (`grep -o 'GI\.GI:EventGraph\.K2Node_[A-Za-z]*_[0-9]*' <sortie find_nodes>`, sorties enregistrées par le client sous `%USERPROFILE%\.claude\projects\D--Game-LifePlay-master-5-8\36e41eab-6dbf-4c01-adea-9fe53389b8ce\tool-results\mcp-unreal-mcp-call_tool-1791907424673.txt` (avant) et `…-1791907595179.txt` (après)) :
```
avant: total 6247, uniques 6247
apres: total 6251, uniques 6251, refPath 6251
-- presents dans une seule liste :
> GI.GI:EventGraph.K2Node_CallFunction_715
> GI.GI:EventGraph.K2Node_CallFunction_720
> GI.GI:EventGraph.K2Node_IfThenElse_219
> GI.GI:EventGraph.K2Node_IfThenElse_220
```
- Dump : `head -n 30176 GI__EventGraph_P2.txt | grep -E '^ [A-Za-z]' | awk '{print $1}' | sort -u | wc -l` → `6249` ; non `K2Node_` → `EdGraphNode_Comment_0`, `EdGraphNode_Comment_1` ; `K2Node_` → `6247` ; `diff` avec la liste MCP avant → code 0.
- Lignes Error / Warning du journal avant la compilation (l. 1990-2329) : sessions MCP (`Unknown session id … client should reinitialize`, `Call to unknown method "server/discover"`, 16.03.25-16.03.26, reconnexion du client), E3 (16.04.18), `LogHttp: Warning: HTTP request timed out … generate_204` (16.05.09) ; 20 `LogAutomationTest: Error: Condition failed` au démarrage (l. 1730-1747…, 15.54.13, tests du moteur au chargement). Aucune liée à GI.
- Lecture seule de Person et Room respectée : ni `load_asset`, ni `save_assets` ; MD5 identiques.