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

313 lines
28 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-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.