LifePlay-Revival/Docs/Migration/etat/ST/STE/STE-H3c-SPEC.md

314 lines
28 KiB
Markdown
Raw Normal View History

Fiche STE-H3c — Niveau N3 — Modèle prévu (modèle de l'agent lp-cart) | utilisé claude-opus-5-5 — Agent lp-cart — Skills sk-protocol, ue-cpp-build, lp-commandlets, lp-paths (préchargés), lp-doc (gabarits)
# STE-H3c-SPEC : lectures `Person[0]` restantes (232 F2 de J3) : garde G12 dans `AddVariable` (2026-10-10)
Lecture seule stricte (aucun éditeur, commandlet, build ni écriture hors de ce fichier). Copie `D:\Game\LifePlay-master 5.8`,
branche `ue5.8`. Gabarit SPEC : `D:\Game\LifePlay-master 5.8\.claude\skills\lp-doc\gabarits.md:36-38`. Suite de `STE-H3-SPEC.md`
(G1-G6) et `STE-H3b-SPEC.md` (G7-G11) : mêmes conventions (H3S § 2.1), gardes G12 et suivantes, risques et questions
préfixés `H3c` (la SPEC STE-H5b, écrite en parallèle, numérote déjà ses R1-R10 et Q-H5b-1).
**Statut : partiel.** Les 232 lignes sont attribuées (une seule source, estimé fort) ; la garde G12 est spécifiée sur le
graphe de données 5.5 mais son câblage d'exécution est **à compléter** : le dump 5.8 d'`AddVariable` avec broches
d'exécution n'existe pas (commande en P1). **Cas B (STE-H5b) : aucune des 232 lignes n'a pour cause l'absence d'`AI`** (§ 1.2).
Abréviations (chemins absolus) :
- **J3** = copie de lecture `%USERPROFILE%\AppData\Local\Temp\claude\D--Game-LifePlay-master-5-8\37530d8d-c780-4a57-8fbd-bcb010aa6408\scratchpad\J3_LifePlay.log`
de `D:\Game\LifePlay_Build_5.8_STF-STE-LISIB_Development\Windows\LifePlay\Saved\Logs\LifePlay.log` (MD5 des deux
`d029de50ffd694b0b7079f82a9ed463f`, `md5sum`, identiques ; `STE-VAL.md:351` : D029DE50…) ;
- **D** = `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\dumps\` ; **CFG** = D `GI__CallFunction_apres-GARDES.txt` ;
**CRBG** = D `GI__CallFunctionReturnBool_apres-GARDES.txt` ; **RSL** = D `GI__ReadSceneLine.txt` ; **CCW** = D `GI__CheckConditionsWho.txt` ;
**EG** = D `GI__EventGraph_apres-GARDES.txt` ;
- **L6f** = `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\portage55\L6f\L6f_dump_GI.txt` (GI **5.5**, `-Fn=* -Pins`, sans
broches d'exécution, d'après `STE-H5b-SPEC.md:12-13`) ;
- **AI** = `D:\Game\LifePlay-master 5.8\Content\Modules\vin_Base\AI\` ; **H3S**, **H3bS**, **H5D**, **H5bS** = `STE-H3-SPEC.md`,
`STE-H3b-SPEC.md`, `STE-H5-DIAG.md`, `STE-H5b-SPEC.md` (dossier `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\`) ;
- **UE** = `D:\Game\Launcher\Engine\UE_5.8\Engine\Source\` (moteur installé, lu).
État du Blueprint : `md5sum "/d/Game/LifePlay-master 5.8/Content/BPs/GI.uasset"` → `b8b97c46b825a6af942baabd5bf74c56` ;
`git status --short -- Content/BPs/GI.uasset` vide ; dernier commit du fichier `5c55db4` (STE-R5). Les dumps `*_apres-GARDES`
décrivent cet état (`STE-VAL.md:352`, `H5bS:10-11`).
## 1. Objectif mesurable
Supprimer, sans changer ce que le jeu fait, les 232 lignes `Script Msg: Attempted to access index 0 from array
'Person_24_4B712C904750AD4CE1580DBEBD9E7396' of length 0 in '/Game/Structs/Variable.Variable'!` de J3 (F2 sans pile :
« called by: GI_C »). Attendu après G12, à parcours comparable : **0** (normalisé par `CHECKING:`, J3 : 232 / 5 490).
### 1.1 Attribution des 232 lignes (source unique : `GI.AddVariable`, remplacement d'une variable existante)
Mécanisme (L6f:10070-10273, GI 5.5, données seulement) : `AddVariable` parcourt `Variables` (`MacroInstance_2707`, L6f:10098-10101),
compare le nom (`EqualEqual_StriStri` `CallFunction_34376` → `IfThenElse_3951`, L6f:10112-10118) et, pour l'entrée de même
nom, lit `Person[0]` de l'**ancienne** valeur : `GetArrayItem_2453`, `Array ← BreakStruct_1527.Person_24_…`, index 0
(L6f:10102-10110, 10164-10167). Sortie vers une macro à broche `InputObject` (`MacroInstance_1960`, IsValid estimé), `SaveSlot`,
`bHidden`, `SavedClothes`, `PersonsUsedThisScene.RemoveItem`, `== PlayerCharacter`, `== nouvelle personne`, `destroyDummy`
(L6f:10167-10273) ; puis `Array_Set` (remplacement, L6f:10119-10124) ou `Array_Add` (ajout). La branche est vivante en 5.8 :
3 « DestroyDummy was from AddVariable » dans J3 (J3:8404, 19889, 20264).
Quand l'ancienne valeur a un tableau `Person` **vide**, la lecture lève F2 et rend `None` (UE, § 6), lu ensuite sans
« Accessed None » (multiligne F2 → `called by` → `Accessed None` sur J3 : **0**) : lecture silencieuse, conforme à une
première consommation par `IsValid`.
Qui écrit des variables à `Person` vide : 19 nœuds `MakeArray` **sans élément** câblés sur une entrée `Person` dans CFG
(Grep multiligne C11), dont ceux des sites `AddVariable` des commandes de routine : `getActorVar` `CallFunction_143` ←
`MakeArray_94` (CFG:4828-4839, 4849-4850), `getBuilding` `_180` ← `MakeArray_139` (CFG:5373-5383, 5393-5394), `getBuildingType`
`_183` ← `MakeArray_138` (CFG:5429-5439, 5450-5451), `findNearbyBuilding` `_199` ← `MakeArray_142` (CFG:5652-5662, 5672-5673).
Aucun dans RSL, CRBG, EG, CCW. L'affectation composée de RSL (`+=`, `-=`… → `AddVariable` `CallFunction_1435`, RSL:511-527)
passe un `MakeArray_92` non vide.
| Groupe (J3) | Lignes | Statut | Empreinte |
|---|---|---|---|
| Image (frame) d'une routine d'IA aboutie (même numéro d'image qu'une ligne `[AI] N moves to`) | **121** | estimé fort | voir ci-dessous |
| Autres images | **111** | estimé | même mécanisme pour les routines arrêtées avant `setCurrentLocation` ; résidu possible, R-H3c-4 |
| Total | **232** | établi (C2) | |
Comptage 121 / 111 : manuel, image par image, sur la liste de 322 lignes de C3 (232 F2, 46 `moves to`, 44 `hours by`) ;
recoupé par deux sous-comptes rejouables : F2 juste avant `[AI] N moves to` = 37 (C5) ; F2 juste après `hours by N` = 24 (C6).
Empreintes (rejouables sur J3) :
- `work_office.lpai` (AI\high_priority\work_office.lpai:8-25) : `Today = AI.getActorVar(…)`, `Work = AI.getBuilding(work)`,
`Type = Work.getBuildingType()` (3 remplacements à `Person` vide), `AI.setCurrentLocation(Work)` (« moves to work »), puis
`Lunch`, `Add`, `Until` (affectations par expression : rien), `AI.setUntil` (« by »), `Today = Today + Add` (1 remplacement).
J3 : **3 F2 avant, 1 après** pour les 7 « moves to work » complets (J3:5697-5705, 8391-8399, 9584-9592, 11980-11988,
16436-16444, 32075-32083, 32183-32191).
- `meal.lpai` (destination `restaurant`) se termine par deux `AI.setActorVar` (meal.lpai:55-56), sans `AddVariable` (site
`CallFunction_162`, CFG:4873-4889) : **0 F2 après « by »** pour les 8 « moves to restaurant » (J3:9771, 10102, 17004, 17032,
17047, 18695, 20542, 21103) ; avant, 2 à 6 F2 selon les variables déjà présentes.
- Ordre temporel : la F2 qui suit la recherche lente `findNearbyBuilding` (≈ 25 ms) tombe après elle, avant `moves to`
(ex. J3:20538 `:475` → 20540 `:500` → 20542 `:501`) : c'est l'`AddVariable` `_199` de `Dest = Current.findNearbyBuilding(…)`.
- Première routine de la partie, sans variable antérieure (J3:2663 « 1 moves to home ») : **0 F2** ; écarte une émission à
la création (et une émission par `GetVariable` du paramètre `Home`/`Dest` de `setCurrentLocation`, `CallFunction_186`, H3S:114-116).
- `random`/`coffee`/`entertainment` : `Today += 1` après « by » (affectation composée remplaçant un `Today` écrit par
`getActorVar`) : 1 F2 après « by » (ex. J3:5190, 6880, 12523).
Exemples d'« autres images » : 13 F2 sur les images 245-271 sans aucun `moves to` (J3:23276-23300), boucle d'un PNJ qui
parcourt ses `.lpai` sans aboutir (condition fausse ou cas B) ; F2 isolées entre deux `CHECKING:` (ex. J3:10466).
### 1.2 Cas B (variable `AI` absente, STE-H5b) : 0 ligne à transférer
- Tous les sites qui lisent `AI` dans les commandes des `.lpai` sont gardés par `IsValidIndex` (G3-G11, CHG-313/314,
`D:\Game\LifePlay-master 5.8\Docs\Journal_Modifications.md:1136-1137`), silencieux sur tableau vide (UE, § 6) : `AI` absente
n'y produit plus de F2.
- Le seul lecteur non gardé connu, `getRelatedPerson` (R13 de H3bS), laisse 2 `property Per` après sa F2 : 0 dans J3 (liste
`-o` des `Accessed None … property X`, C10 : aucune `Per`).
- La lecture d'`AddVariable` ne dépend pas d'`AI` : elle dépend de l'ancienne valeur de la variable écrite (`Today`, `Current`,
`Dest`, `Work`, `Type`…). Une partie non mesurable des 111 « autres » est émise **pendant** des suites de routines en cas B
(muettes en J3 depuis G4/G5, `H5bS:210`), sans en être causée : STE-H5b en réduira le nombre (routines abouties plus tôt,
moins de `.lpai` par PNJ ; `H5bS:268` attend un rapport F2 / `CHECKING:` ≤ 0,042), sans supprimer le mécanisme. G12 le supprime.
## 2. Fichiers touchés, ordre
Un seul fichier : `Content\BPs\GI.uasset`, graphe de fonction **`AddVariable`** (2 nœuds créés, 1 `break_pins`, 5 `connect_pins`
attendus). Ni `CallFunction`, ni `ReadSceneLine`, ni l'EventGraph, ni les `MakeArray`, ni le C++, ni le contenu des modules.
Ordre : G12 est indépendante de STE-H5b (qui insère un appel `AddVariable('AI')` dans l'EventGraph, H5bS:110) ; les deux
écrivent `GI.uasset` : IMPL **successives**, instantané et MD5 propres à chacune (P2). L'appel ajouté par H5b passe par G12 :
ancienne valeur `[AIDummy]` (longueur 1), donc chemin `then`, sans effet.
### 2.0 Préalables (dans l'ordre, avant tout `create_node`)
- **P1 (bloquant, à compléter)** : dump 5.8 avec broches d'exécution, même commande que P3 de H5b (`H5bS:6-7`) :
`.\Tools\RunCommandlet.ps1 -Lot STE-D -Commandlet LPDumpFunction -Args '-BP=GI -Fn=AddVariable -Pins -Exec'`, copié en
`dumps\GI__AddVariable_D4.txt`. Puis remplir le tableau du § 2.2 (colonnes « 5.8 »). Sans P1 : arrêt sur G12, aucune improvisation.
- P2 : MD5 de `GI.uasset` = `b8b97c46…` (ou la valeur relevée à la fin de l'IMPL H5b) ; sinon refaire P1.
- P3 : gel annoncé (lp-mcp § 1.7), `.\Tools\Snapshot.ps1 -Lot STE-H3c` (`GI.uasset`), `AssetTools.load_asset` `/Game/BPs/GI`.
- P4 : `get_node_infos {nodes:[{refPath:"/Game/BPs/GI.GI:AddVariable.K2Node_<Nom>"}]}` pour chaque nœud existant cité ; liens = P1,
sinon arrêt.
### 2.1 Conventions
Reprises de H3S § 2.1 (`H3S:55-70`) : `type_id` IsValidIndex = `Utilitaires|Tableau|IsValidIndex`, Branch =
`Utilitaires|ContrôleDeFlux|Branche` ; Branch entrée exécution 0 / `Condition` 1, sorties `then` 0 / `else` 1 ; IsValidIndex
`TargetArray` (entrée 1 attendue), `Index` (entrée 2, laissé à `0`, relu), `ReturnValue` (sortie 0) **relus par `get_node_infos`** ;
après le graphe : `compile_blueprint` + `hyper_blueprint_debug_inspect {blueprintAssetPath:"/Game/BPs/GI.GI", graphName:"AddVariable"}`
= 0 diagnostic ; `save_assets {asset_paths:["/Game/BPs/GI"]}`.
### 2.2 G12 — `AddVariable`, lecture de `Person[0]` de l'ancienne valeur (232 F2 de J3) — modèle G7 / G8
| Rôle | 5.5 (L6f) | 5.8 (P1, à compléter) |
|---|---|---|
| Élément de la boucle sur `Variables` | `BreakStruct_1527` (L6f:10102-10111) | |
| Test du nom, sortie vraie = X | `IfThenElse_3951.then` (L6f:10117-10118 ; broche d'exécution non dumpée en 5.5) | |
| Lecture fautive | `GetArrayItem_2453`, `Array ← BreakStruct_1527.Person_24_…`, `Dimension 1 = '0'` (L6f:10164-10167) | |
| Premier consommateur exécuté de la sortie = M | `MacroInstance_1960.InputObject` (L6f:10168-10169), macro IsValid **estimée** | |
| Entrée d'exécution de M ← source S | à lire (attendu : `IfThenElse_3951.then` ou un nœud qui le suit) | |
| Cible(s) de `Is Not Valid` = Y | à lire | |
Après (à exécuter une fois le tableau rempli) : IsValidIndex `G12-I`, Branch `G12-B` ; `break_pins` (`S.<sortie>`, `M.exec`) ;
`connect_pins` (5) : 1. `S.<sortie>` → `G12-B.execute` (0) ; 2. `BreakStruct_<5.8>.Person_24_4B712C904750AD4CE1580DBEBD9E7396` →
`G12-I.TargetArray` ; 3. `G12-I.ReturnValue` → `G12-B.Condition` (1) ; 4. `G12-B.then` (0) → `M.exec` ; 5. `G12-B.else` (1) →
chaque cible de Y (rien si `Is Not Valid (vide)`). `G12-I.Index` = `0` (relu).
Comportement : aujourd'hui, ancienne valeur à `Person` vide → F2, sortie remise au défaut (`None`) → IsValid faux → `Is Not
Valid` → Y. Après : `IsValidIndex` faux, sans message → `else` → Y. **Identique** (estimé fort ; établi si P1 montre que M
est la macro IsValid et qu'aucun autre consommateur de la sortie ne s'exécute hors de sa branche `Is Valid`). Ancienne
valeur avec une personne : `then` → M, chemin d'origine inchangé (y compris `destroyDummy`).
Arrêts de G12 (rapport, pas de correctif) : M n'est pas un IsValid ; la sortie de la lecture alimente un nœud exécuté hors de
`Is Valid` ; plusieurs lectures `Person_24_…[0]` dans le graphe 5.8 (chacune demande sa ligne de tableau) ; nœuds 5.8 sans
correspondance avec L6f.
### 2.2 bis G12 — nœuds 5.8 relus sur le dump STE-D5 — complément A-CART pour l'orchestrateur LOT STE (2026-10-10)
Auteur : agent lp-cart (A-CART), claude-opus-5-5, skills sk-protocol, ue-cpp-build, lp-commandlets, lp-paths ; lecture
seule, seuls ce fichier et `STE-H5b-SPEC.md` écrits. Dump **AV** = `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\dumps\GI__AddVariable_D5.txt`
(`-BP=GI -Fn=AddVariable -Pins -Exec`, lot STE-D5, 20:51:17, code 0, 49 nœuds, AV:120 ; AV:367-416 = écho tronqué du même
dump). `GI.uasset` non modifié depuis 17:33:20 (`stat -c '%y %s'`), MD5 `b8b97c46…`, `git status` vide : AV décrit l'état
actuel (établi). **P1 est fait** (fichier `_D5`, lot `STE-D5`, au lieu de `_D4` / `STE-D`). Les nœuds cités par le § 2.2
portent dans AV les noms de L6f (R-H3c-1 levé pour ce graphe).
| Rôle | 5.5 (L6f) | 5.8 (AV, établi) |
|---|---|---|
| Élément de la boucle sur `Variables` | `BreakStruct_1527` | `K2Node_BreakStruct_1527` : `Variable` ← `MacroInstance_2707.Array Element` ; `Person_24_…` → `GetArrayItem_2453.Array` (AV:159-168) |
| Test du nom, sortie vraie = X | `IfThenElse_3951.then` | `K2Node_IfThenElse_3951` : `execute` ← `MacroInstance_2707.LoopBody` ; `Condition` ← `CallFunction_34376.ReturnValue` (`EqualEqual_StriStri`) ; `then` → `MacroInstance_1960.exec` ; `else` (vide) (AV:174-178) |
| Lecture fautive | `GetArrayItem_2453` | `K2Node_GetArrayItem_2453` : `Array` ← `BreakStruct_1527.Person_24_…`, `Dimension 1 = '0'`, `Output` → 8 entrées (AV:238-241) |
| Premier consommateur exécuté = M | `MacroInstance_1960`, IsValid estimée | `K2Node_MacroInstance_1960`, **macro `'IsValid'`** (AV:242) : `exec` ← `IfThenElse_3951.then` (seul lien) ; `InputObject` ← `GetArrayItem_2453.Output` ; `Is Valid` → `IfThenElse_4367.execute` ; `Is Not Valid` → `CallArrayFunction_4346.execute` (AV:243-246) |
| Entrée d'exécution de M ← source S | à lire | `IfThenElse_3951.then` (sortie 0) |
| Cible de `Is Not Valid` = Y | à lire | `K2Node_CallArrayFunction_4346` = `Array_Set(Variables, MacroInstance_2707.Array Index, MakeStruct_614)` ; `execute` ← `MacroInstance_1960.Is Not Valid`, `IfThenElse_4367.else`, `IfThenElse_4819.then`, `CallFunction_606.then` ; `then` → `VariableSet_3566` (`Replaced = true`) → `Knot_488` → `MacroInstance_2707.Break` (AV:179-186, 201-205, 215-217) |
**`MacroInstance_1960` = IsValid : estimation confirmée** (AV:85, 242).
Arrêts du § 2.2, contrôlés sur AV :
1. M est un IsValid : oui.
2. Consommateurs de `GetArrayItem_2453.Output` (AV:241) : `MacroInstance_1960.InputObject` ; `VariableGet_19165.self`
(`SaveSlot` → `CallFunction_27614` → `IfThenElse_4367.Condition`) ; `VariableGet_142.self` (`bHidden` → `Not`),
`CallFunction_24845.A` (`== PlayerCharacter`), `CallFunction_1.A` (`==` nouvelle), `VariableGet_1.self` (`SavedClothes` →
`Length > 0`), tous vers `BooleanOR_236` → `IfThenElse_4819.Condition` ; `CallArrayFunction_5493.Item` ;
`CallFunction_0.Dummy`. Les nœuds exécutés qui les lisent sont `IfThenElse_4367` (`execute` ← `Is Valid` seul, AV:256),
`IfThenElse_4819` (← `IfThenElse_4367.then` seul, AV:279), `CallArrayFunction_5493` et `CallFunction_0` (chaîne
`IfThenElse_4819.else` → `CallFunction_2` → `5493` → `0`, AV:264, 298, 313) : **tous sous `Is Valid`** (établi).
3. Une seule lecture d'un élément de `Variables` : `Person_24_… -> K2Node_GetArrayItem_2453.Array` (AV:167) ; les deux
autres `GetArrayItem` lisent des paramètres (`GetArrayItem_0` ← `Person`, `GetArrayItem_8856` ← `Float`, AV:230-231,
303-304), hors G12.
4. Correspondance avec L6f : complète.
**G12 est exécutable.**
Câblage exact (outils Epic, un appel à la fois ; `refPath` `/Game/BPs/GI.GI:AddVariable.K2Node_<Nom>`), après P2 et P3 :
1. P4 : `get_node_infos` de `IfThenElse_3951`, `MacroInstance_1960`, `BreakStruct_1527`, `GetArrayItem_2453`,
`CallArrayFunction_4346` : liens = tableau ci-dessus ; relever les indices de `MacroInstance_1960.exec` (entrée, attendu 0),
de `BreakStruct_1527.Person_24_…` (sortie) et de `CallArrayFunction_4346.execute` (entrée, attendu 0).
2. `create_node {graph:{refPath:"/Game/BPs/GI.GI:AddVariable"}, type_id:"Utilitaires|Tableau|IsValidIndex", pos:{x,y}}` →
**G12-I** ; `get_node_infos` : entrées `TargetArray` 0 et `IndexToTest` 1 (= `0`), sortie `ReturnValue` 0, valeurs relevées
en 5.8 sur `CallArrayFunction_8` à `_14` (GIMPL = `STE-GARDES-IMPL.md`:38 ; CFG:7619-7623). **Correction du § 2.1** : la
broche s'appelle `IndexToTest` (indice 1), pas `Index` (2), et `TargetArray` a l'indice 0.
3. `create_node` `type_id:"Utilitaires|ContrôleDeFlux|Branche"` → **G12-B** (entrées `execute` 0, `Condition` 1 ; sorties
`then` 0, `else` 1, lp-mcp § 3).
4. `break_pins` : `IfThenElse_3951.then` (sortie 0) / `MacroInstance_1960.exec` (entrée, indice relu en 1).
5. `connect_pins` : `IfThenElse_3951.then` (0) → `G12-B.execute` (0).
6. `connect_pins` : `BreakStruct_1527.Person_24_4B712C904750AD4CE1580DBEBD9E7396` → `G12-I.TargetArray` (0) ; broche
générique, typée `Person` au câblage (H3S:65-66) ; le lien vers `GetArrayItem_2453.Array` reste.
7. `connect_pins` : `G12-I.ReturnValue` (0) → `G12-B.Condition` (1).
8. `connect_pins` : `G12-B.then` (0) → `MacroInstance_1960.exec`.
9. `connect_pins` : `G12-B.else` (1) → `CallArrayFunction_4346.execute` (5e lien entrant ; une entrée d'exécution en
accepte plusieurs, H3bS:78-79).
10. Relire `G12-I.IndexToTest` = `0` (ne le poser que s'il diffère).
11. `get_node_infos` de G12-I, G12-B et des 5 nœuds de l'étape 1 : liens = « Après ».
12. `compile_blueprint` avertissements en erreurs (`hyper_blueprint_debug_inspect` est absent du serveur, GIMPL:44-46 : il
remplace celui du § 2.1 et du § 7.2) ; `save_assets {asset_paths:["/Game/BPs/GI"]}` ; fermeture, `UeState.ps1` = 0, MD5 relevé.
Volume : **2 nœuds, 1 `break_pins`, 5 `connect_pins`, 0 `set_pin_value`** (+1 relecture) ; `AddVariable` après = **51 nœuds**
(§ 7.1 : `=== GI :: AddVariable (51 noeuds) ===`).
Après (liens attendus) : `IfThenElse_3951.then` → `G12-B.execute` (seul) ; `G12-B.Condition` ← `G12-I.ReturnValue`, `then` →
`MacroInstance_1960.exec` (seul lien entrant de M), `else` → `CallArrayFunction_4346.execute` ; `G12-I.TargetArray` ←
`BreakStruct_1527.Person_24_…`, `IndexToTest = 0` ; `BreakStruct_1527.Person_24_…` → `GetArrayItem_2453.Array`,
`G12-I.TargetArray` ; `CallArrayFunction_4346.execute` ← `MacroInstance_1960.Is Not Valid`, `IfThenElse_4367.else`,
`IfThenElse_4819.then`, `CallFunction_606.then`, `G12-B.else` ; aucun autre nœud modifié.
Comportement : **identique** (établi, les deux conditions du § 2.2 étant vérifiées). Ancienne `Person` vide : aujourd'hui F2
puis `Is Not Valid` → `Array_Set` → `Replaced` → `Break` ; après, `IsValidIndex` faux sans message → `else` → le même
`Array_Set`. Ancienne `Person` non vide : `then` → M, chemin d'origine (y compris `destroyDummy`). Nom différent, ajout
(`Array_Add`), cas `choice` du `SwitchString_75` : non touchés. Appel `AddVariable('AI')` de STE-H5b : ancienne `AI` =
`[AIDummy]` (longueur 1) → `then`, sans effet.
**Réponse à Q-H3c-1** : P1 a été lancé par l'orchestrateur (STE-D5, partagé avec P3 de H5b) et le § 2.2 est complété ici, dans
la forme du § 2.4 bis de H3bS ; une fiche courte n'est pas nécessaire. Statut de la SPEC : **complète, exécutable** sous
P2-P4. Ordre avec STE-H5b : IMPL successives (P2 : MD5 de départ = `b8b97c46…` ou M1 de H5b, qui ne touche pas
`AddVariable`) ; si le témoin de H5b est posé (`STE-H5b-SPEC.md` § 2.7), G12 se fait avant l'instantané `STE-H5b-temoin` ou
après sa restauration, jamais entre les deux.
Tours du complément (A-CART, commun à `STE-H5b-SPEC.md` § 2.0 bis et § 2.7) : 19 / 50.
## 3. Repli
- Avant écriture : instantané `.\Tools\Snapshot.ps1 -Lot STE-H3c` (P3), MD5 de départ relevé (P2).
- Échec de compilation, diagnostic, lien relu différent : arrêt, `.\Tools\Restore.ps1 -Lot STE-H3c` éditeur fermé (GI entier),
contrôle MD5 = valeur de P2.
- Après commit (gardien) : `git revert` du commit du ticket STE-H3c (indépendant de ceux de H3, H3b, H5b).
## 4. Risques R#, questions Q#
- **R-H3c-1** : nœuds de G12 lus sur L6f (GI 5.5 du 2026-09-30, sans exécution) ; aucune fiche ST ne cite `AddVariable` parmi
les fonctions modifiées (CHG-313/314 : `CallFunction`, `CallFunctionReturnBool`, `setActorVar`, `getActorVar`,
`ReturnStatIfNeeded`), mais le portage 5.8 a pu renommer : P1 et P4 tranchent.
- **R-H3c-2** : `AddVariable` sert toutes les variables de scène (sites de `CallFunction`, `ReadSceneLine`, EventGraph `AI`,
`Companion`, `PregTemp`, `ImpregTemp`, H5D:58-59) : une erreur de câblage touche tout le moteur de scènes. Critères § 7.1-7.3
obligatoires avant commit.
- **R-H3c-3** : attribution des 121 lignes estimée forte (empreintes du § 1.1) ; des 111 autres, estimée (même mécanisme
attendu). Le message F2 ne nomme pas la fonction (UE, § 6) : la VAL tranche (§ 7.3).
- **R-H3c-4** : lecteurs silencieux candidats, non observés dans J3 (attribution incertaine), **non retenus** : C1 `CheckConditionsWho`
`GetArrayItem_3268` → IsValid `MacroInstance_2601` (`Is Not Valid` → `VariableSet_5`) (CCW:180-204) ; C2 EventGraph `GetArrayItem_935`
→ IsValid `MacroInstance_72` (`Is Not Valid (vide)`) (EG:6963-6966, 29107-29111). Même forme que G12 ; si un reste F2 > 0
après G12 : fiche de suite (dumps présents).
- **R-H3c-5** : alternative écartée : donner un élément `[None]` aux 19 `MakeArray` vides de CFG. Change le résultat de
`Array_Length(Person) > 0` dans `ReadSceneLine` (RSL:616-628 : `Person = Person[0]` au lieu de `PlayerCharacter`, RSL:375-381)
pour les lignes de statistiques sur ces variables : comportement modifié, hors Q1 = A.
- **R-H3c-6** : masquage : nul. La lecture fautive ne sert que le chemin « ancienne personne absente », qui ne fait rien
d'autre que `Is Not Valid`.
- **Q-H3c-1 (orchestrateur)** : lancer P1 (commande unique, partagée avec P3 de H5b) puis compléter le § 2.2 par un complément
de SPEC (forme du § 2.4 bis de H3bS), ou confier le complément à une fiche courte.
- **Q-H3c-2 (utilisateur, facultative)** : traiter C1 et C2 par précaution (gardes à comportement identique) ou seulement si un
reste apparaît en VAL (recommandation : seulement si reste).
## 5. Interdits
- Aucune modification de `CallFunction`, `ReadSceneLine`, `CheckConditionsWho`, de l'EventGraph, des `MakeArray`, du C++.
- Aucune correction de contenu (`Content\Modules\…`), aucun nœud AND / OR / Select pur, aucun `FunctionResult` créé, aucun
`delete_node`. Pas d'IMPL de G12 sans P1 à P4.
- Pas d'écriture HyperAIStudio (lp-mcp § 1.1) ; outils Epic seulement. Pas de commit par l'agent : ticket au gardien (lp-repo).
## 6. Valeurs moteur lues dans le moteur installé (UE = `D:\Game\Launcher\Engine\UE_5.8\Engine\Source\`)
- `GenericArray_Get` : index invalide → message « Attempted to access index %d from array '%s' of length %d in '%s'! » avec,
pour `%s` final, le chemin du **propriétaire de la propriété tableau** (ici la structure `Variable`, pas la fonction appelante),
puis élément remis au défaut (`None`) : `Runtime\Engine\Private\KismetArrayLibrary.cpp:459-479` (message l. 472-478, `ResetToDefault` l. 479).
- `GenericArray_IsValidIndex` : test sans message : `Runtime\Engine\Private\KismetArrayLibrary.cpp:583-591`.
## 7. Critères de VAL (commande → attendu)
1. Dump après IMPL : `.\Tools\RunCommandlet.ps1 -Lot STE-H3c -Commandlet LPDumpFunction -Args '-BP=GI -Fn=AddVariable -Pins -Exec'` →
nœuds = P1 + 2 ; liens du § 2.2 relus ; `python Tools\DiffRemplacementNoeuds.py <P1> <après> <profil>` sans autre écart.
2. `hyper_blueprint_debug_inspect` 0 diagnostic (`AddVariable`) ; `CompileAllBlueprints` éditeur fermé : 0 erreur ;
`LPTestStringCompat` 3120 / 0 / 60 (lp-validate).
3. Journal de jeu (build Development, parcours de J3 : `STE-J3.md:10-16`), Grep en mode `count` :
- `Person_24_4B712C904750AD4CE1580DBEBD9E7396' of length 0` → **0** (J3 : 232) ; un reste > 0 → rapport, attribution
à C1 / C2 (R-H3c-4), pas de correctif improvisé ;
- multiligne `Person_24[^\n]*\r?\n[^\n]*called by[^\n]*\r?\n[^\n]*\[AI\] \d+ moves to` → 0 (J3 : 37) ;
multiligne `hours by \d+\r?\n[^\n]*Person_24` → 0 (J3 : 24) ;
- `DestroyDummy was from AddVariable` → présent, même ordre que J3 (3) : branche « ancienne personne valide » intacte ;
- non-régression : `hours by [1-9]` ≥ 1 (J3 : 46), `\[AI\] \d+ moves to` ≥ 1 (J3 : 46), `index SPAWN` > 0 (J3 : 151),
dénominateur `CHECKING:` (J3 : 5 490) ;
- inchangés à 0 : `property Person in`, `CallFunc_Array_Get_Item_3[0-3] `, `CallFunc_Array_Get_Item_41 ` ;
- information : `Attempted to access index` (J3 : 336, dont 104 sur d'autres tableaux, hors périmètre).
4. Puis `& .\Tools\LogStats.ps1 -Compare <journal>,<J3>` : aucune famille nouvelle.
Fichiers à commiter (dépôt jeu, branche `ue5.8`, ticket au gardien) :
- A `Docs/Migration/etat/ST/STE/STE-H3c-SPEC.md`
Tours : 45 / 60
## Constats
Commandes (outil Grep sauf mention ; J3 = copie de lecture) et comptes bruts :
- C1 (Bash) `cp` du journal J3 vers le scratchpad puis `md5sum` des deux : `d029de50ffd694b0b7079f82a9ed463f` × 2.
- C2 `Attempted to access index 0 from array 'Person_24_` (count) → **232**.
- C3 `\d\d\.\d\d\.\d\d:\d{3}\]\[[ \d]+\](LogScript: Warning: Script Msg: Attempted|LogBlueprintUserMessages: \[AI\] \d+ moves to \w*|LogBlueprintUserMessages: \[GI_C_\d+\] \(test0104\) for [\d.]+ hours by \d+)`
(`-o`) → 322 lignes (base du comptage 121 / 111).
- C4 multiline `Attempted to access index 0 from array 'Person_24[^\n]*\r?\n[^\n]*called by[^\n]*\r?\n[^\n]*Accessed None` → **0**.
- C5 multiline F2 → `called by` → `\[AI\] \d+ moves to` → 37 ; C6 multiline `hours by \d+\r?\n[^\n]*Person_24` → 24 ;
C7 multiline `\[AI\] \d+ moves to[^\n]*\r?\n[^\n]*hours by` → 46 ; `moves to .*\(test0104\)` → 46.
- C8 `Attempted to access index` → 336 ; C9 `Attempted to access index \d+ from array '(?:Person|Float|String|Building|Bool)' of length|DestroyDummy was from AddVariable|DestroyDummy test1903 via AddVariable`
(`-o`) → 6 lignes, toutes `DestroyDummy` (J3:8403-8404, 19888-19889, 20263-20264) : aucune F2 sur le paramètre `Person` d'`AddVariable`.
- C10 `Accessed None trying to read (\(real\) )?property \w+` (`-o`) → 80 lignes (`SexInterface`, `K2Node_CustomEvent_Person`,
`CallFunc_GetSkeletalMesh_ReturnValue*`, `ThemeSong`, `GI`, `K`…), aucune `Per` ni `Person`.
- C11 multiline `K2Node_MakeArray_\d+ +K2Node_MakeArray\r?\n[^\n]*Array +-> K2Node_CallFunction_\d+\.Person\r?\nLogLPDump: Warning: K2Node_`
sur CFG, RSL, CRBG, EG, CCW → 19 nœuds, tous dans CFG (`MakeArray_15, 19, 27, 11, 72, 65, 83, 93, 94, 109, 102, 1, 139, 138,
142, 158, 162, 101, 174`).
- C12 `Person_24_4B712C904750AD4CE1580DBEBD9E7396` (count, glob `*__*.txt` sous `etat\ST`) → 1 109 sur 20 fichiers ; lecteurs
non encore gardés lus : RSL `GetArrayItem_2243` gardé par `Array_Length > 0` (RSL:616-628) ; CCW `_3268`, EG `_935` (R-H3c-4) ;
EG `_45`, `_49` → `ModifyStat.self` (EG:24474-24478, 24508-24512 : lèveraient « Accessed None », 0 dans J3, C4).
- C13 (Bash) `md5sum` de `GI.uasset` → `b8b97c46…` ; `git log --oneline -2 -- Content/BPs/GI.uasset` → `5c55db4`, `c70082d`.
- Lu : L6f:10070-10273 (`AddVariable` 5.5, 49 nœuds) ; CFG:120-164, 4828-4889, 5373-5451, 5622-5673 ; CRBG:1584-1590, 2255-2380
(`isString`, `isOpen`, `isSameBuilding`, `isBuildingValid` : aucune lecture `Person_24`) ; RSL:296-385, 484-543 ;
AI : `entertainment`, `home`, `random`, `coffee`, `high_priority\work_hourly`, `sleep`, `meal`, `so_follows`, `work_office`.
- Écarts de méthode : un appel Bash `ls … | grep` a servi à lister deux dossiers (présence de `STE-H5b-SPEC.md` et absence de
dump `AddVariable` / `GetVariable` / `isString` sous `dumps\`) au lieu de Glob ; lp-mcp non invoqué : conventions MCP reprises
de H3S § 2.1. Aucun dump 5.8 d'`AddVariable`, `GetVariable` ni `isString` (C13, listage ci-dessus).
- Constat annexe : `GetVariable` n'est pas l'émetteur (estimé) : la première routine (J3:2663) appelle
`setCurrentLocation(<variable écrite par getBuilding, Person vide>)` via `GetVariable` (`CallFunction_186`) sans F2.