45 KiB
Fiche STE-H5b — 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-mcp (lu, § 1-4), lp-doc (gabarits)
STE-H5b-SPEC : reposer la variable de scène AI avant chaque routine d'IA (correctif F-a) (2026-10-10)
Lecture seule stricte (aucun éditeur, commandlet, build ni écriture hors de ce fichier). Gabarit SPEC :
D:\Game\LifePlay-master 5.8\.claude\skills\lp-doc\gabarits.md:36-38. Décision de l'utilisateur : Q-H5-1 = « Corriger (F-a) »
(STE-TACHES.md:23). Statut : complet, sous un préalable : le dump 5.8 d'AddVariable avec broches d'exécution
(P3, commande au § 2.0) n'existe pas. Le reste de la SPEC est exécutable ; P3 contrôle 3 points (A1-A3) avant l'IMPL.
Abréviations (chemins absolus) :
- EG =
D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\dumps\GI__EventGraph_apres-GARDES.txt(-Fn=EventGraph -Pins -Exec, 17:43:39, après les gardes, EG:1-4 ; 6233 nœuds, EG:120) ; - L6f =
D:\Game\LifePlay-master 5.8\Docs\Migration\etat\portage55\L6f\L6f_dump_GI.txt(GI 5.5 du 2026-09-30,-Fn=* -Pins, sans broches d'exécution : le flux de données seulement,L6f_LPDumpFunction_20260930-102202.txt:1) ; - L2 =
D:\Game\LifePlay_Build_5.8_STB-JEU2_Development\Windows\LifePlay\Saved\Logs\LifePlay.log(avant les gardes) ; - L3 =
D:\Game\LifePlay_Build_5.8_STF-STE-LISIB_Development\Windows\LifePlay\Saved\Logs\LifePlay.log(J3, état actuel B8B97C46) ; - H5D =
STE-H5-DIAG.md, H3S =STE-H3-SPEC.md, H3bS =STE-H3b-SPEC.md, GIMPL =STE-GARDES-IMPL.md(dossierD:\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 (rejoué) : 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). EG a été pris après
l'IMPL des gardes (GIMPL § 1 : B8B97C46 à 17:33), donc EG décrit le GI actuel (établi).
1. Objectif mesurable
Que chaque PlayScene d'un fichier .lpai lancé par la boucle d'IA (MacroInstance_45) soit précédé, dans la même
exécution synchrone, de AddVariable('AI', [AIDummy]). Un vidage de Variables par UpdateCheckForScenes
(CallArrayFunction_5412, EG:6616-6623) ne peut se produire qu'à une reprise latente (Delay(0) de la macro Async,
§ 6) ; il ne peut donc plus tomber entre la pose de AI et la routine qui la lit.
Mesures :
- statique : EG après IMPL = 6234 nœuds (+1), liens du § 2.4 relus, compilation sans diagnostic (§ 7, V1-V3) ;
- en jeu (J4, même parcours que J3 plus une rafale) :
hours by 0= 0 ; routines valides en hausse par rapport à J3 (ratios du § 7, V5) ; aucune famille d'avertissements nouvelle.
Volume : 1 nœud créé, 1 break_pins, 6 connect_pins, 2 set_pin_value (+1 relecture), 0 suppression, un seul
graphe (EventGraph).
Ce que l'utilisateur verra (effet accepté par Q-H5-1) :
- en temps accéléré ou après un déplacement (rafale de routines), la routine d'un PNJ (repas, travail, sortie…)
s'applique à ce PNJ : il change de lieu (
setCurrentLocation) et reçoit sa prochaine échéance (AI_Untils[slot]) ; aujourd'hui, une partie de ces routines tourne « à vide » (sans personne, effets masqués par les gardes G4-G10) et le PNJ est repris à la seconde suivante ; - moins de routines jouées par PNJ : la boucle s'arrête au premier
.lpaiqui pose une échéance future (condition C deBooleanAND_65, EG:24880-24887, 24792-24796) ; - les compteurs du PNJ (
ActorVars, ex.entertainment_today,entertainment.lpai:19-20) avancent au bon moment, ce qui évite des répétitions ; on croise plus souvent un PNJ au lieu où sa routine l'envoie ; - journal : plus de lignes
(test0104) for … hours by <n>et[AI] <n> moves to …pendant les rafales ; - rien d'autre : scènes du joueur, interface, PNJ hors routine inchangés (§ 4, R5).
2. Fichiers touchés, ordre
Un seul fichier : Content\BPs\GI.uasset, graphe EventGraph (événement UpdateAI, corps de MacroInstance_45). Ni
UpdateCheckForScenes, ni CallFunction_739 / _779, ni les fonctions AddVariable / CallFunction, ni les gardes
G1-G11, ni le C++, ni le contenu des modules.
2.0 Préalables (dans l'ordre, avant tout create_node)
- P1. Décision Q-H5-1 = F-a : acquise (
STE-TACHES.md:23). Q-H5b-1 (preuve, § 4) : à demander avant J4, pas avant l'IMPL. - P2. MD5 de
GI.uasset=b8b97c46…etgit statusvide sur ce fichier. Sinon : nouveau dump.\Tools\RunCommandlet.ps1 -Lot STE-H5b -Commandlet LPDumpFunction -Args '-BP=GI -Fn=EventGraph -Pins -Exec'et comparaison des nœuds du tableau 2.2 ; tout écart arrête l'IMPL. - P3 (à compléter, bloquant) — dump 5.8 d'
AddVariableavec flux d'exécution, éditeur fermé, BUILD-GO de Big Boss (une session à la fois sur la copie UE,STE-TACHES.md:41-45) :.\Tools\RunCommandlet.ps1 -Lot STE-H5b -Commandlet LPDumpFunction -Args '-BP=GI -Fn=AddVariable -Pins -Exec'(≈ 1 min, comme EG:3). Le flux de données 5.5 est lu dans L6f:10070-10273 ; le dump 5.8 doit confirmer :- A1 remplacement par nom : boucle sur
Variables(MacroInstance_2707, L6f:10098-10101), égalité sans casse du nom (EqualEqual_StriStriCallFunction_34376, L6f:10112-10118) →Array_Setà l'indice trouvé (CallArrayFunction_4346, L6f:10119-10124) etReplaced = true(L6f:10139-10145) ; sinonArray_Addà la fin (CallArrayFunction_3373, L6f:10083-10087). Attendu : jamais deux entréesAI; - A2 la branche
destroyDummy(CallFunction_0, L6f:10212-10215) n'est atteinte que pour l'entrée remplacée, si elle est valide (MacroInstance_1960IsValid, L6f:10168-10169), siSaveSlot == 0(IfThenElse_4367, L6f:10170-10179) et si le OUBooleanOR_236est faux (ancienne = joueur, non cachée, ancienne = nouvelleCallFunction_1, a desSavedClothes; L6f:10188-10224, 10262-10273) ; - A3 le
SwitchString_75surName(L6f:10149-10151, casOptionChosen…→VariableSet_14216) laisseAIsur le chemin par défaut (même chemin queCallFunction_739aujourd'hui). Un point non confirmé → arrêt, rapport à l'orchestrateur, pas d'IMPL. Facultatif (non bloquant) :... -Args '-BP=GI -Fn=Async -Pins -Exec'(la macro est un graphe deGetAllGraphs, donc trouvée par-Fn, § 6).
- A1 remplacement par nom : boucle sur
- P4. Gel annoncé à toutes les sessions (lp-mcp § 1.7) ; instantané
.\Tools\Snapshot.ps1 -Lot STE-H5b -Path Content\BPs\GI.uasset(paramètres-Lot,-Pathobligatoires,Tools\Snapshot.ps1:17-22) ; tag d'entréeSTE-H5b-avantpar le gardien si l'orchestrateur le souhaite ; éditeur headless (lp-mcp § 2) ;AssetTools.load_asset/Game/BPs/GI. - P5.
get_node_infos {nodes:[{refPath:"/Game/BPs/GI.GI:EventGraph.K2Node_<Nom>"}]}pour chaque nœud du tableau 2.2 : les liens doivent égaler la colonne « avant » ; relever au passage la position (pos) deIfThenElse_148et deCallFunction_743, et les indices de broches. - P6.
find_node_types {graph:{refPath:"/Game/BPs/GI.GI:EventGraph"}, type_id_filter:"AddVariable", context_pins:[]}: attenduScène|AddVariable(relu en STE-H3b pourCallFunction_360, GIMPL:33, 39). Autre résultat → arrêt.
2.0 bis P3 contrôlé sur le dump 5.8 — complément A-CART pour l'orchestrateur LOT STE (2026-10-10, après STE-D5)
Auteur : agent lp-cart (A-CART), claude-opus-5-5, skills sk-protocol, ue-cpp-build, lp-commandlets, lp-paths ; lecture
seule, seul ce fichier et STE-H3c-SPEC.md écrits. Dumps (sous D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\dumps\) :
AV = GI__AddVariable_D5.txt (-BP=GI -Fn=AddVariable -Pins -Exec, lot STE-D5, 20:51:17, code 0,
=== GI :: AddVariable (49 noeuds) === AV:120 ; le bloc AV:367-416 est l'écho tronqué du même dump) ; AS =
GI__Async_D5.txt (-Fn=Async, 20:52:03, code 0, 20 nœuds, AS:120 ; écho AS:210-259). GI.uasset : dernière écriture
17:33:20 (stat -c '%y %s' → 2026-10-10 17:33:20 … 52540467), MD5 b8b97c46…, git status vide : AV et AS décrivent
l'état B8B97C46 (établi). Tous les nœuds cités par P3 existent dans AV sous le même nom que dans L6f.
P3 est satisfait : A1, A2 et A3 sont confirmés ; la SPEC est exécutable (P1, P2, P4-P6 restent à faire à l'IMPL).
- A1 confirmé (établi, sauf la sortie de
Break, estimée forte). EntréeFunctionEntry_3606.then→SwitchString_75(AV:122) ;Default→MacroInstance_2707(ForEachLoopWithBreaksurVariables, AV:151-158, 219).LoopBody→IfThenElse_3951(AV:174-178), conditionEqualEqual_StriStri(CallFunction_34376, AV:169-173 :A← paramètreNameparVariableGet_19198,B←BreakStruct_1527.Name_2_…) : comparaison sans casse ;elsevide → élément suivant.then→MacroInstance_1960(IsValid), dont toutes les issues finissent surArray_Set(CallArrayFunction_4346, AV:179-186 :Index←MacroInstance_2707.Array Index,Item←MakeStruct_614) →VariableSet_3566Replaced = true(AV:201-205) →Knot_488→MacroInstance_2707.Break(AV:154, 215-217).Completed→IfThenElse_4283surReplaced(AV:206-212) :thenvide,else→Array_Add(CallArrayFunction_3373, AV:134-140).Replacedest une variable locale (ses nœuds n'ont pas de brocheself, AV:201-205, 211-212, au contraire des variables de GI, AV:133, 229 ; estimé fort), remise à sa valeur par défaut à chaque appel (H3bS:100-102). Conclusion : la première entrée de même nom est remplacée sur place et la boucle s'arrête ;Array_Addseulement si aucune entrée ne porte ce nom.AddVariablene crée jamais une deuxième entréeAI. SiBreakne menait pas àCompleted(macro standard, non dumpée), il n'y aurait pas d'ajout non plus : A1 tient dans les deux cas. - A2 confirmé (établi).
destroyDummy(CallFunction_0, AV:297-302) n'est atteint que par :IfThenElse_3951.then→MacroInstance_1960Is Valid(anciennePerson[0]=GetArrayItem_2453, AV:238-246) →IfThenElse_4367surSaveSlot == 0(CallFunction_27614, AV:247-259)then→IfThenElse_4819(AV:278-282)else, conditionBooleanORCommutativeAssociativeBinaryOperator_236(AV:283-289) de : A ancienne== PlayerCharacter(CallFunction_24845, AV:270-274) ; BNot(ancienne.bHidden)(CallFunction_565, AV:290-296) ; C ancienne==nouvellePerson[0](CallFunction_1←GetArrayItem_0du paramètrePerson, AV:303-311) ; DLength(ancienne.SavedClothes) > 0(CallFunction_5, AV:355-366). Suite de la branche :PrintString« DestroyDummy test1903 via AddVariable » (CallFunction_2) →Array_RemoveItem(PersonsUsedThisScene)(CallArrayFunction_5493) →destroyDummy(Dummy = ancienne, KeepAlreadyGot = false)→PrintString« (test0304) DestroyDummy was from AddVariable » (CallFunction_606,bPrintToScreen = false) →Array_Set(AV:263-269, 297-333). Pour H5-A, cas attendu : ancienneAI=[AIDummy]posée parCallFunction_739juste avant la boucle, même objet que la nouvelle :SaveSlot != 0(seule condition d'entrée duelsedeIfThenElse_148, § 2.5) ferme la branche dèsIfThenElse_4367, et le terme C la fermerait aussi. Cas d'un autre objet (siAIDummychangeait entre deux images ; écrivain hors GI, R3) : la branche ne s'ouvre que pour une ancienne personne àSaveSlot == 0, cachée, hors joueur, sansSavedClothes; c'est le comportement d'origine d'AddVariable, déjà possible avec_739/_779(incertain, non observé ; V5 compteDestroyDummy was from AddVariable). R2 : levé pour le cas attendu. - A3 confirmé, libellé corrigé (établi).
SwitchString_75(AV:218-223) :Selection← paramètreName; un seul cas, la brochechoice(et non «OptionChosen…» : L6f:10149-10155, sans broches d'exécution, ne montrait pas le nom du cas ;OptionChosenIndexest la variable écrite) →VariableSet_14216OptionChosenIndex = Round(Float[0])(CallFunction_71442,GetArrayItem_8856, AV:224-237), dontthenest vide (AV:226) : pourName = choice, rien n'est enregistré dansVariables. Broche cachéeNotEqual_StriStri(AV:222) : comparaison sans casse (estimé, nom de la fonction).AI≠choice→Default→ A1 (établi). LePrintStringCallFunction_4(« Add Variable ») aexecutevide (AV:344-345) : jamais exécuté (cohérent avec 0 ligneAdd Variabledans L3, R2). - Autres constats utiles à l'IMPL (établis sur AV) : aucun nœud latent ni
FunctionResultparmi les 49 nœuds (types, AV:121-366) : H5-A rend la main de façon synchrone, puisH5-A.then→CallFunction_743;Float[0]n'est lu que sur le caschoice(GetArrayItem_8856) : leMakeArray_5vide de H5-A ne lève pas de F2 ;Person[0]de l'ancienne entrée (GetArrayItem_2453) n'est lu qu'après un nom égal : ancienneAIde longueur 1, pas de F2 (lecture que G12 garde,STE-H3c-SPEC.md§ 2.2 bis).
§ 2.3 confirmé sans changement : type_id Scène|AddVariable (relu en 5.8, GIMPL:39 ; P6 le revérifie) ; broches de
H5-A = paramètres d'AddVariable Name, Class, Array, Bool, Float, String, Person, Building (AV:121-130), même ordre que
CallFunction_739 (EG:25149-25160, qui montre aussi self, EG:25152 : l'indice exact reste à relire, § 2.1) ; valeurs
Name = 'AI', Class = 'Person', Array = 'false' copiées telles quelles dans la structure (MakeStruct_614 ←
VariableGet_18510 à _18516, Building ← entrée, AV:141-150, 187-200 ; Class et Array ne sont testés nulle part).
Volume inchangé : 1 nœud, 1 break_pins, 6 connect_pins, 2 set_pin_value (+1 relecture) ; EG après = 6234 nœuds.
Macro Async (AS), sémantique relue (établi sauf mention) :
Tunnel_0.execute→IfThenElse_0sur l'entréeCondition(BooleanAND_65pourMacroInstance_45, EG:25423) ;else→Knot_3→Completed(AS:129-133, 178-180) : condition fausse = fin de la boucle, pas de pause.then→IfThenElse_2surSkipAsync(variable de GI, AS:181-188) : vrai →SkipAsync = false,Local = -1,Delay(0)(AS:189-198) ; faux →IfThenElse_1sur(Local % ItersPerTck == 0) AND (Local >= 0)(AS:141-155, 200-209).IfThenElse_1.then→Knot_1→ExecutionSequence_0:then_0→Loop Body, puisthen_1→Knot_2(AS:163-172) ;IfThenElse_1.else→Delay(0)(CallFunction_2,Duration = 0, AS:156-162),then→Knot_2.Knot_2→AssignmentStatement_0Local = Local + 1→ retour àIfThenElse_0(AS:134-138, 173-177).Local(TemporaryVariable_0, AS:139-140) n'est pas remis à zéro à l'entrée. Conséquences :
- Le corps (
IfThenElse_148→ H5-A →PlayScene) s'exécute en entier surthen_0, avantthen_1; le seul point latent de la macro est leDelay(AS:156) : pas de reprise entre la pose deAIet la routine (objectif du § 1, établi). - Correction du § 2.5 (« jusqu'à
len(LPAI)itérations à 3 par image ») : le corps ne part que siLocal % 3 == 0(ItersPerTck = '3', EG:25424) ; les deux valeurs suivantes deLocalpassent chacune par unDelay(0). Le gestionnaire d'actions latentes ne traite un objet qu'une fois par passe (bProcessedThisFrame, UERuntime\Engine\Private\LatentActionManager.cpp:223-231, 250-257) : environ un.lpaitoutes les deux images (estimé fort). Entre deux.lpaid'un même PNJ, il y a toujours au moins une reprise latente, donc une fenêtre de vidage : F-a reste nécessaire à chaque itération (rien à changer au § 2.3). - Ligne F-b du § 2.6 et « Incertain » des Constats : la sortie d'
Asyncquand la condition devient fausse est établie (Completed, fin de boucle) ; F-b arrêterait la boucle d'IA au lieu de la suspendre (verdict « plus invasive » confirmé).
Corrections de renvois : V4 (§ 7) joint dumps\GI__AddVariable_D5.txt (et non GI__AddVariable.txt) ; R1 et R2 (§ 4) sont
levés par ce complément ; la commande P3 du § 2.0 n'est plus à lancer.
Tours du complément (A-CART, commun au § 2.7 et à STE-H3c-SPEC.md § 2.2 bis) : 19 / 50.
2.1 Conventions (reprises de H3S § 2.1, H3bS § 2.1 et GIMPL § 2)
refPathd'un nœud :/Game/BPs/GI.GI:EventGraph.K2Node_<Nom>(lp-mcp § 3) ; G-H2 a déjà été posée dans ce graphe (GIMPL:35).- Indices de broches par direction. Établis :
IfThenElsesortiethen0 /else1 (lp-mcp § 3). Tous les autres se relisent parget_node_infosavantconnect_pins. Attendus (estimés) pour le nouvelAddVariable: entréesexecute0,Name1,Class2,Array3,Bool4,Float5,String6,Person7,Building8, sortiethen0, si la broche cachéeselfn'est pas comptée (cas observé : IsValidIndexTargetArray= 0, GIMPL:38) ; sinon +1 sur chaque entrée aprèsexecute.CallFunction_743: entréeexecute0.MakeArray_3à_6: sortieArray0. - Une sortie de données peut alimenter plusieurs entrées (les liens existants restent) ; une entrée d'exécution peut recevoir plusieurs liens (H3bS:78-79).
- Après le graphe :
compile_blueprintavec avertissements en erreurs (hyper_blueprint_debug_inspectabsent du serveur, GIMPL:44-46), puissave_assets {asset_paths:["/Game/BPs/GI"]}.
2.2 Nœuds existants (colonne « avant », EG)
| Nœud | Rôle | Liens avant (EG) |
|---|---|---|
K2Node_MacroInstance_45 |
macro Async, ItersPerTck = 3 |
Loop Body → IfThenElse_148.execute ; Completed → VariableSet_280 ; Condition ← BooleanAND_65 (EG:25422-25428) |
K2Node_IfThenElse_148 |
AIDummy.SaveSlot == 0 |
execute ← MacroInstance_45.Loop Body ; Condition ← CallFunction_811 ; then → VariableSet_292.execute ; else → CallFunction_743.execute (EG:25750-25754) |
K2Node_CallFunction_811 / VariableGet_576 |
SaveSlot de VariableGet_529.AIDummy == 0 |
EG:25742-25749 |
K2Node_CallFunction_743 |
PlayScene(LPAI[CheckingPkgIndex]) |
execute ← MacroInstance_43.LoopBody, IfThenElse_148.else ; then → MacroInstance_47 ; FilePath ← GetArrayItem_51.Output (EG:24891-24895) |
K2Node_MacroInstance_43 |
WhileLoop mort |
execute (vide), LoopBody → CallFunction_743.execute (EG:24975-24979) |
K2Node_CallFunction_739 |
AddVariable existant, modèle |
execute ← VariableSet_259.then ; then → VariableSet_281.execute ; Name = 'AI', Class = 'Person', Array = 'false' ; Bool ← MakeArray_4, Float ← MakeArray_5, String ← MakeArray_6, Person ← MakeArray_3, Building (vide) (EG:25149-25160) |
K2Node_MakeArray_4 / _5 / _6 |
tableaux vides Bool / Float / String |
Array → CallFunction_739.Bool / .Float / .String (EG:25161-25166) |
K2Node_MakeArray_3 |
[AIDummy] |
Array → CallFunction_739.Person ; [0] ← VariableGet_525.AIDummy (EG:25167-25169) |
K2Node_VariableGet_525 |
AIDummy |
AIDummy → MakeArray_3.[0] (EG:25170-25172) |
2.3 Étapes MCP (une par appel, dans l'ordre ; le nouveau nœud est noté H5-A)
create_node {graph:{refPath:"/Game/BPs/GI.GI:EventGraph"}, type_id:"Scène|AddVariable", pos:{x,y}}; position libre près deIfThenElse_148(sans effet sur l'exécution).get_node_infosde H5-A : appelGI_C::AddVariable, mêmes broches queCallFunction_739(EG:25149-25160) ; noter son nom (K2Node_CallFunction_<n>) et les indices réels (§ 2.1). Sinon arrêt et repli (§ 3).break_pins:IfThenElse_148.else(sortie 1) /CallFunction_743.execute(entrée 0).connect_pins:IfThenElse_148.else(1) →H5-A.execute.connect_pins:H5-A.then→CallFunction_743.execute(0). Le lien mortMacroInstance_43.LoopBodyreste.connect_pins:MakeArray_3.Array→H5-A.Person.connect_pins:MakeArray_4.Array→H5-A.Bool.connect_pins:MakeArray_5.Array→H5-A.Float.connect_pins:MakeArray_6.Array→H5-A.String.set_pin_value:H5-A.Name=AI(valeur relue surCallFunction_739, EG:25153).set_pin_value:H5-A.Class=Person(EG:25154).- Relire
H5-A.Array: doit valoirfalse(EG:25155) ; ne le poser que s'il diffère.Building: rien. get_node_infosde H5-A,IfThenElse_148,CallFunction_743,CallFunction_739,MakeArray_3à_6: liens = § 2.4.compile_blueprint(avertissements en erreurs) : 0 erreur, 0 avertissement ; puissave_assets.- Fermeture (lp-mcp § 2 :
Stop-Process,.\Tools\UeState.ps1= 0), MD5 après relevé,git status --short -- Content Config Source.
Repli documenté de l'étape 6 seulement : si connect_pins refuse MakeArray_3.Array → H5-A.Person, créer un Make Array
(type_id Utilitaires|Array|Faireuntableau, GIMPL:39), câbler d'abord sa sortie Array → H5-A.Person (typage,
H3bS:83-84), puis VariableGet_525.AIDummy → [0] (2 nœuds au lieu de 1, EG 6235). Tout autre refus → arrêt et repli.
2.4 Après (liens attendus, relus à l'étape 13 et dans le dump V1)
IfThenElse_148.else→H5-A.execute(seul lien) ;H5-A:execute←IfThenElse_148.else;then→CallFunction_743.execute;Name = 'AI',Class = 'Person',Array = 'false';Bool←MakeArray_4.Array,Float←MakeArray_5.Array,String←MakeArray_6.Array,Person←MakeArray_3.Array,Building(vide) ;CallFunction_743.execute←MacroInstance_43.LoopBody,H5-A.then;MakeArray_3/_4/_5/_6:Array→CallFunction_739.<broche>etH5-A.<broche>;- aucun autre nœud de EG modifié.
2.5 Comportement avant / après
- Avant :
AIposée une fois par PNJ (CallFunction_739, EG:25149-25171), puis jusqu'àlen(LPAI)itérations à 3 par image (MacroInstance_45, EG:25422-25428) ; un vidage entre deux images retireAIpour les.lpaisuivants (H5D § 3-4). - Après : à chaque itération qui joue un
.lpai(SaveSlot != 0),AIest reposée juste avantPlayScene. SiAIexiste déjà avec le mêmeAIDummy,AddVariablela remplace par elle-même (A1) ; cette situation existe déjà à chaque PNJ (CallFunction_779poseAIdansLoopUpdateAI, EG:25017-25037, puisCallFunction_739la repose dansUpdateAI). - Validité de
AIDummyau point d'insertion (point (a) de la fiche) : leelsedeIfThenElse_148n'est pris que siAIDummy.SaveSlot != 0; une lecture sur une référence nulle rend 0 (UEScriptCore.cpp:3234-3245), doncAIDummyn'est jamais nul quand H5-A s'exécute (établi par construction). Même source (VariableGet_525) que l'appel actuel. - Le
.lpais'exécute en entier dans l'appelPlayScene: boucleWhileLoopMacroInstance_963sur les lignes, tant queNot(WaitingScene)(EG:6027-6031, 6212-6223) ;WaitingScenene passe à vrai qu'après une ligne « lourde » (LastHeavyFunction, EG:20369-20390) = ligne commençant pargenerateoudress(GI__ReadSceneLine.txt:635-652) ; les 17.lpaidu jeu n'en ont pas (Grep\.(generate|dress)|^\s*\w+\s*=\s*generate|\bdress\(,-i,*.lpaisousContent\Modules: 0). - Gardes G1-G11 : avec
AI=[AIDummy]valide, les testsIsValidIndex/IsValiddes gardes qui lisentAI(G1, G2, G3, G4, G5, G6, G7, G8, G9, G10, G11 selon la commande) passent parthen: le chemin d'origine s'exécute. Le cas B ne les déclenche plus ; elles restent utiles au cas A (conditions de.lpscene) et aux autres variables (ex.SOdeso_follows.lpai:8-17).
2.6 Alternatives comparées (fiche, point (c) ; aucune n'est tranchée ici)
| Variante | Où | Nœuds / coupures | Effet hors IA | Verdict de lecture |
|---|---|---|---|---|
| F-a (décidée) | corps de MacroInstance_45 |
1 / 1 | aucun | la plus petite ; couvre tout .lpai synchrone |
F-a′ : déplacer CallFunction_739 dans la boucle |
idem | 0 / 3 | aucun | même effet, plus de coupures, sans gain |
F-b : exclusion mutuelle (nextAi ou CheckingForScenes dans une condition Async) |
MacroInstance_39 ou _45 |
1-2 | cadence des scènes du joueur ou des routines ; une condition fausse fait sortir la macro (branche IfThenElse_0 sur Condition, L6f:49499-49505 ; sortie exacte à lire avec -Fn=Async -Exec) au lieu de la mettre en pause |
plus invasive |
F-c : ne pas vider Variables pendant la boucle d'IA (Branch sur nextAi avant Array_Clear) |
UpdateCheckForScenes |
2 / 1 | la vérification d'une scène candidate garderait les variables de la candidate précédente et des .lpai (ex. Today, Current, Dest) : appariement WHO des scènes du joueur modifié |
risque visible sur les scènes du joueur |
F-c′ : sauver puis reposer AI autour du Array_Clear |
UpdateCheckForScenes |
≥ 4 (GetVariable, IsValidIndex + Branch, AddVariable, Make Array) | chemin chaud (5 490 CHECKING: en J3, STE-VAL.md:364) ; AI visible des candidates, sans lecteur (Grep (^|[^A-Za-z_])AI\. sur *.lpscene : 0) |
plus de nœuds, aucun gain pour le contenu actuel |
Lecture : aucune alternative n'est plus sûre que F-a sans effet de bord ; F-a reste conforme à la décision.
2.7 Témoin temporaire (Q-H5b-1) — complément A-CART pour l'orchestrateur LOT STE (2026-10-10)
Décision de l'utilisateur : Q-H5b-1 = témoin (STE-TACHES.md:27) : un PrintString temporaire sur le chemin « personne
vide » de G5, dans un build de diagnostic non commité, retiré avant le commit. Il remplace la variante (b) du § 4 (texte
et préfixe ci-dessous) ; la mesure « avant F-a » de cette variante devient la contre-épreuve C0 (fin de section).
Nœuds existants, graphe CallFunction de GI (CFG = dumps\GI__CallFunction_apres-GARDES.txt, 1563 nœuds, CFG:120 ;
état B8B97C46, graphe que l'IMPL H5b ne touche pas) :
| Nœud | Rôle | Liens (CFG) |
|---|---|---|
K2Node_IfThenElse_14 |
G5-B1 : IsValidIndex(BreakStruct_54.Person_24_…, 0) (CallArrayFunction_9) |
execute ← CallFunction_189.then ; then → IfThenElse_15.execute ; else (vide) (CFG:7619-7628) |
K2Node_IfThenElse_15 |
G5-B2 : IsValid(GetArrayItem_75.Output) (CallFunction_356) |
execute ← IfThenElse_14.then ; then → CallFunction_190.execute (Map_Add(AI_Untils)) ; else (vide) (CFG:7629-7637) |
K2Node_CallFunction_193 |
modèle : PrintString « (test0104) for … hours by <clé> » après _190 |
bPrintToScreen = 'true', bPrintToLog = 'true', WorldContextObject (vide) (CFG:5586-5596) |
Nœuds créés (noms réels K2Node_CallFunction_<n>, notés à la création) :
- T1 =
PrintStringsurIfThenElse_14.else,InString=STE-H5b-TEMOIN G5-B1 setUntil Person vide(variable absente ou sans personne : le cas B que F-a supprime) ; - T2 =
PrintStringsurIfThenElse_15.else,InString=STE-H5b-TEMOIN G5-B2 setUntil Person0 nul(variable présente,Person[0]nul : autre cause, hors F-a) ; - pour les deux :
bPrintToScreen=false(commeCallFunction_606, AV:329),bPrintToLog=true(défaut, relu) ;TextColor,Duration,Key,WorldContextObject: défaut / vide (commeCallFunction_193). Texte ASCII seul ; préfixe unique :STE-H5b-TEMOIN→ 0 dans L3 (Grep, modecount), témoin de lecture du même fichierLogBlueprintUserMessages: \[GI_C_\d+\] \(test0104\)→ 46 ; - ligne attendue :
LogBlueprintUserMessages: [GI_C_<n>] STE-H5b-TEMOIN G5-B1 setUntil Person vide(préfixe[objet]quandKismet.bLogPrintStringSourceest vrai, UERuntime\Engine\Private\KismetSystemLibrary.cpp:497-506, observé pour les messages existants de GI) ; type_idduPrintString: non relu en 5.8 (absent de lp-mcp § 3 et de GIMPL § 2) ; il se lit à l'étape T-2.
Étapes MCP (une par appel ; refPath /Game/BPs/GI.GI:CallFunction.K2Node_<Nom>) :
- T-1.
get_node_infosdeIfThenElse_14etIfThenElse_15: liens = tableau ci-dessus (les deuxelsevides) ; sinon arrêt. - T-2.
find_node_types {graph:{refPath:"/Game/BPs/GI.GI:CallFunction"}, type_id_filter:"PrintString", context_pins:[]}; sans résultat, filtresPrintpuisImprimer. Retenir l'entrée dont le nœud créé appelleKismetSystemLibrary::PrintString(brochesInString,bPrintToScreen,bPrintToLog,TextColor,Duration,Key), pasPrintText(InText). Aucune entrée conforme → arrêt, pas de témoin, preuve par la variante (a) (V5 seul), rapport à l'orchestrateur. - T-3.
create_nodeT1 (position libre près deIfThenElse_14) ;get_node_infosT1 : nom, indices deexecute,InString,bPrintToScreen(attenduexecuteentrée 0 ; les autres relus,self/WorldContextObjectcachés possibles). - T-4.
connect_pins:IfThenElse_14.else(sortie 1) →T1.execute. - T-5.
set_pin_value:T1.InString=STE-H5b-TEMOIN G5-B1 setUntil Person vide. - T-6.
set_pin_value:T1.bPrintToScreen=false. - T-7 à T-10. Idem pour T2 sur
IfThenElse_15.else(sortie 1),InString=STE-H5b-TEMOIN G5-B2 setUntil Person0 nul. - T-11.
get_node_infosde T1, T2,IfThenElse_14,IfThenElse_15:else→ T1 / T2 seuls,theninchangés,T1.thenetT2.thenvides, textes relus à l'octet. - T-12.
compile_blueprint(avertissements en erreurs) : 0 / 0 ;save_assets {asset_paths:["/Game/BPs/GI"]}. Volume : 2 nœuds, 0break_pins, 2connect_pins, 4set_pin_value;CallFunction1563 → 1565 nœuds (dump facultatif, éditeur fermé :.\Tools\RunCommandlet.ps1 -Lot STE-H5b -Commandlet LPDumpFunction -Args '-BP=GI -Fn=CallFunction -Pins -Exec'). Comportement : T1 et T2 sont sur deselsevides et n'ont aucune sortie de données ; seule différence, une ligne de journal (établi par construction).
Procédure (décision de l'utilisateur ; une session sur la copie, gel annoncé, BUILD-GO de Big Boss) :
- IMPL H5b finie (§ 2.3, étapes 1-15) : GI enregistré, éditeur fermé (
.\Tools\UeState.ps1= 0), MD5 M1 relevé (V3), dump V1 (EventGraph, 6234 nœuds) pris sur M1. - Instantané dédié :
.\Tools\Snapshot.ps1 -Lot STE-H5b-temoin -Path Content\BPs\GI.uasset(lot distinct deSTE-H5b, qui garde B8B97C46 : la première sauvegarde d'un lot fait référence,Tools\Snapshot.ps1:7-9) ; MD5 de la copieD:\Game\LifePlay_Backup_5.5\STE-H5b-temoin\Content\BPs\GI.uasset= M1, sinon arrêt. - Éditeur headless (lp-mcp § 2),
load_asset/Game/BPs/GI, T-1 à T-12, fermeture,UeState.ps1= 0, MD5 M2 (≠ M1, relevé, jamais commité). - Build Development de diagnostic (mêmes commandes que
STF-T5-J-BUILD.md:8-10) :.\Tools\Build.ps1 -Lot STE-H5b -Target LifePlay -Config Development -ExtraArgs "-NoUBA"puis.\Tools\BuildDebug.ps1 -Config Development -ArchiveDir "D:\Game\LifePlay_Build_5.8_STE-H5b-TEMOIN_Development" -SkipBuild(dossier absent avant).PrintStringest compilé en Development (retiré seulement en Shipping / Test, UEKismetSystemLibrary.cpp:458). - J4 sur cette archive (parcours de V5, avec rafale) ; journal
D:\Game\LifePlay_Build_5.8_STE-H5b-TEMOIN_Development\Windows\LifePlay\Saved\Logs\LifePlay.log. - Retrait, éditeur fermé :
.\Tools\Restore.ps1 -Lot STE-H5b-temoin(-Lotobligatoire,Tools\Restore.ps1:19-24) ; MD5 = M1 ;git status --short -- Content Config Source=M Content/BPs/GI.uassetseul ; V2 (CompileAllBlueprints) sur M1. Seulement alors : ticket au gardien (commit de GI à M1). MD5 ≠ M1 → arrêt, pas de commit. - L'archive
..._STE-H5b-TEMOIN_Developmentest gardée (jamais supprimée), marquée « diagnostic, GI M2 non commité » dans le livrable J4 ; elle ne sert de référence à aucun autre lot. Interdit pendant la fenêtre 2-6 : toute autre écriture deGI.uasset(G12 de STE-H3c en particulier), que la restauration défairait. Si G12 doit être mesurée dans la même J4, son IMPL se place avant l'étape 2 (l'instantané couvre alors H5b + G12). Écart assumé : J4 se joue sur M2, le commit porte M1 ; la seule différence est T1 / T2 (ci-dessus).
Critère (Grep en mode count sur le journal de J4) :
STE-H5b-TEMOIN→ 0 ; détailSTE-H5b-TEMOIN G5-B1(cas B, critère de F-a) etSTE-H5b-TEMOIN G5-B2;- non-vacuité, même journal :
hours by [1-9]≥ 1 (G5 atteinte avec une personne) etLogBlueprintUserMessages: \[GI_C_\d+\]≥ 1 (lesPrintStringde GI arrivent au journal) ; rafale présente (V5) ; - reste > 0 : rapport (compte, trois lignes de contexte par occurrence), pas de correctif. Attribution :
setUntilest appelé surAIpar les 17.lpai, mais aussi par 6.lpscene(Actor.setUntil× 5 sousvin_Incest\Scenes\proactive,CurrentCompanion.setUntildansgoodbye_companion.lpscene:11; Grep\b\w+\.setUntil\b-i -osousContent\Modules: 23 lignes) ; la boucle d'IA ne tourne jamais pendant une scène du joueur (R5) : une ligne témoin pendant une scène n'est pas imputable à F-a (contexte à lire, incertain).
Contre-épreuve sans F-a (C0, jugée utile) : depuis G5 (Q2), le cas B est muet et J3 ne dit pas combien il y en a eu ; un
0 en J4 seul ne distingue pas « F-a agit » de « parcours sans cas B » (sa fréquence dépend des rafales : 24 by 0 dans L2,
H3S:151-152). C0 montre, avec le même témoin et un parcours comparable, que le cas B se produit sans F-a. Attendu C0 :
STE-H5b-TEMOIN G5-B1 ≥ 1 (rapporté aussi au nombre de CHECKING:) ; J4 est alors lue à parcours comparable (CHECKING:
du même ordre). Coût : une écriture de GI, un build, une session et une restauration de plus (les 2 builds de la variante (b)
du § 4). Ordre conseillé, qui laisse intacte la procédure ci-dessus : juste après P4 (instantané STE-H5b = B8B97C46) et
avant l'IMPL H5b : T-1 à T-12 sur B8B97C46 (mêmes refPath : H5b ne touche pas CallFunction), build vers
D:\Game\LifePlay_Build_5.8_STE-H5b-C0_Development, session C0, .\Tools\Restore.ps1 -Lot STE-H5b éditeur fermé, MD5 =
b8b97c46…, puis IMPL H5b. Décision à l'utilisateur (elle ajoute un build à sa procédure) ; sans C0, le 0 de J4 est
rapporté « sans contrôle positif ».
3. Repli
- Avant écriture : instantané P4 (
LifePlay_Backup_5.5\STE-H5b, étatb8b97c46…). - Échec de création, lien relu différent, refus non prévu (§ 2.3) ou compilation avec diagnostic : arrêt,
.\Tools\Restore.ps1 -Lot STE-H5béditeur fermé (GI entier), contrôle MD5 =b8b97c46b825a6af942baabd5bf74c56. - Après commit (gardien) :
git revertdu commit du ticket STE-H5b, ou tagSTE-H5b-avant(ticket RESTORE). - Indépendant des gardes : le repli de H5b ne défait aucune garde (instantané pris sur l'état B8B97C46).
4. Risques R#, questions Q#
- R1 (A1) : sémantique d'
AddVariablelue sur un dump 5.5 sans exécution (L6f:10070-10273). Attendu : remplacement par nom sans casse. Indice concordant : si chaque appel ajoutait une entrée, chaque PNJ aurait deuxAI(_779puis_739) sans effet visible ; non probant seul. P3 tranche. - R2 (A2) : la branche
destroyDummyd'AddVariableest vivante en 5.8 : 3 déclenchements dans L3 (Grepvia AddVariable|DestroyDummy was from AddVariable| Add Variable→ 6 lignes, L3:8403-8404, 19888-19889, 20263-20264 ; 0 dans L2). PourAIelle ne doit pas se déclencher : ancienne personne = nouvelle (AIDummy), etSaveSlot != 0au point d'insertion (§ 2.5). Estimé fort ; P3 confirme ; en J4, ce compte ne doit pas croître (V5). - R3 (point (a)) : l'écrivain de
GI.AIDummyn'est pas trouvé. EG : seulsVariableSet_258et_276, sur des chaînes sans entrée d'exécution (EG:25011-25016, 25362-25376) ; L6f (GI 5.5 complet) : aucun autreVariableSetd'AIDummy(GrepAIDummy: 39 lignes, hors EG seulementdestroyDummyL6f:42252-42258,destroySlotL6f:43747-43750 et un nom de variable de scène'AIDummy'dansGenerateHomeAndWork, L6f:43339, 43459) ;PC__EventGraph.txt: 0. Il est donc posé hors de GI (autre Blueprint ou niveau, non dumpé). Non bloquant :AIDummyest non nul au point d'insertion (§ 2.5), c'est la même lecture queCallFunction_739, et les routines valides l'impriment sous le nom d'objetAI([AI] <n> moves to …: 48 lignes dans L3, 9 dans L2 ; estimé : message dePerson_C::setCurrentLocationsurAIDummy). - R4 : une ligne « lourde » (
generate…,dress…) dans un futur.lpaisuspendrait la routine (minuterieContinueScene) ; un vidage pourrait alors tomber entre deux lignes, hors de portée de F-a. Aujourd'hui : 0 cas (§ 2.5). - R5 (masquage, fiche § 5) : seule l'entrée nommée
AIest remplacée (A1). Aucun contenu n'écritAI =(Grep^\s*AI\s*=-isousContent\Modules: 0) ; aucune.lpscenene litAI.(0) ; les 17.lpaila lisent (95 lignes). La condition deMacroInstance_45contientNot(SceneOn)(CallFunction_748, EG:25586-25592) etLen(followUp) == 0(CallFunction_828, EG:25979-25990) : H5-A ne s'exécute jamais pendant une scène du joueur. Chaque candidate deUpdateCheckForScenescommence parArray_Clear:AIn'entre pas dans une vérification. - R6 (comportement modifié, accepté) : routines appliquées, moins de routines par PNJ, compteurs
ActorVarsavancés (§ 1). - R7 (preuve) : depuis les gardes (Q1 = A), une routine sans personne est muette (G4 et G5 sautent
setCurrentLocationetsetUntilsans message) : le journal ne peut plus montrer directement « aucun vidage suivi de routine sans personne ». La preuve directe est statique (§ 2.5) ; la preuve en jeu est statistique (V5) — voir Q-H5b-1. - R8 : variables laissées dans
Variablespar la vérification des scènes (après un vidage) et variables temporaires des.lpai(Today,Current,Dest,Until) : comportement d'origine inchangé ; chaque.lpairecrée ses temporaires avant de les lire (ex.entertainment.lpai:7-16, estimé pour les 16 autres). - R9 : réemploi de
MakeArray_3à_6par deux appels : précédent G10 (CallFunction_360câblé sur les Make Array deCallFunction_203, H3bS:159-160, GIMPL:33 ; compilé, J3 PASS). Un nœud pur est réévalué pour chaque appel qui le lit (estimé fort, non relu dansKismetCompiler.cpp). - R10 : coût : un parcours de
Variablespar.lpaijoué (≤ 17 par PNJ) ; négligeable (estimé).
Q-H5b-1 (utilisateur, avant J4) — preuve en jeu : (a) statistique seule, comparaison J4 / J3 (V5, défaut) ; ou
(b) témoin temporaire dans un build de diagnostic non commité : un PrintString « (test0104) setUntil sans personne »
sur IfThenElse_14.else (G5-B1, CallFunction, GIMPL:28), mesuré avant F-a (attendu > 0 dans une rafale) puis après
(attendu 0), retiré par Restore.ps1 avant le commit (2 builds de plus, une écriture GI de plus).
5. Interdits
- Aucune modification hors du § 2.3 : pas de
delete_node, pas de retouche deCallFunction_739/_779, deUpdateCheckForScenes(CallArrayFunction_5412), des conditions des macrosAsync, des gardes G1-G11, du C++, du contenu (*.lpai,*.lpscene). - Aucun nœud AND / OR / Select ; aucune écriture HyperAIStudio (lp-mcp § 1.1) ; outils Epic seulement.
- Pas d'IMPL sans P1 à P6 (P3 compris) ; pas d'éditeur pendant un commandlet ou un build (lp-mcp § 1.7).
- Pas de commit par l'agent ni par l'IMPL : ticket au gardien (lp-repo) ; numéro CHG à réserver par l'orchestrateur
(
etat\REPO\NUMEROS.md).
6. Valeurs moteur lues dans le moteur installé (UE 5.8)
Delay(0):FDelayAction::UpdateOperationretire le temps écoulé et ne déclenche la suite que lorsqueTimeRemaining <= 0(UERuntime\Engine\Public\DelayAction.h:27-30) : la reprise est latente, traitée par le gestionnaire d'actions latentes, jamais au milieu d'une chaîne d'exécution synchrone. La macroAsyncn'a pas d'autre point de suspension que ceDelay(CallFunction_2,Duration = 0, L6f:49523-49527).- Référence nulle : l'expression est sautée et la valeur rendue effacée (UE
Runtime\CoreUObject\Private\UObject\ScriptCore.cpp:3234-3245, messageAccessed Nonel. 3208-3216) :AIDummy.SaveSlotvaudrait 0 sur un nul, doncIfThenElse_148.then. UBlueprint::GetAllGraphsparcourt aussiMacroGraphs(UERuntime\Engine\Private\Blueprint.cpp:1969-1991) ;LPDumpFunctionfiltre ce tableau parGraph->GetName()(Source\LifePlayEditorTools\LPDumpFunctionCommandlet.cpp:131-158) :-Fn=Asyncest accepté (précédent :=== GI :: Async (20 noeuds) ===, L6f:49498).
7. Critères de VAL (commande → attendu)
- V1 — dump après IMPL :
.\Tools\RunCommandlet.ps1 -Lot STE-H5b -Commandlet LPDumpFunction -Args '-BP=GI -Fn=EventGraph -Pins -Exec'→=== GI :: EventGraph (6234 noeuds) ===(6235 avec le repli de l'étape 6) ; diff avec EG : seulement le bloc H5-A et les lignes deIfThenElse_148.else,CallFunction_743.execute,MakeArray_3à_6(Array), conformes au § 2.4. - V2 —
compile_blueprintsans diagnostic (IMPL) ;CompileAllBlueprintséditeur fermé : 0 erreur, 0 avertissement nouveau (lp-validate). - V3 — MD5 de
GI.uasset≠b8b97c46…, relevé au CHG ;git status --short -- Content Config Source=M Content/BPs/GI.uassetseul. - V4 — P3 conforme (A1, A2, A3) et joint au lot (
dumps\GI__AddVariable.txt). - V5 — J4 en jeu (build Development, parcours de
STE-J3.md:10-16plus une rafale : déplacement par la carte vers un autre lieu, lignesUPDATE TIME ARRIVED/LOAD ROOM, et une action de plusieurs heures), Grep en modecountsur leLifePlay.logde J4, J3 (L3) comme référence :
| Motif | Attendu J4 | J3 (L3) |
|---|---|---|
hours by 0 |
0 | 0 (STE-VAL.md:360) ; L2 : 24 |
hours by [^0] / CHECKING: |
≥ 46 / 5 490 (0,0084) | 46 / 5 490 (STE-VAL.md:363-364) |
LogBlueprintUserMessages: \[AI\] / CHECKING: |
≥ 48 / 5 490 (0,0087) | 48 (rejoué) |
DestroyDummy was from AddVariable |
même ordre que J3 (pas de rafale liée aux routines) | 3 (rejoué) |
Person_24_4B712C904750AD4CE1580DBEBD9E7396' of length 0 / CHECKING: |
≤ 0,042 | 232 / 5 490 (STE-VAL.md:361) |
property Person in, CallFunc_Array_Get_Item_3[0-3] , _41 |
0 | 0 (STE-VAL.md:356-358) |
DestroyDummy was from CheckScenes, WHO unmatched |
> 0 (des vidages ont eu lieu pendant le parcours) | 106 (rejoué) |
Puis & .\Tools\LogStats.ps1 -Compare <journal J4>,<L3> : aucune famille d'erreur ou d'avertissement nouvelle. Les
ratios dépendent du parcours (R7) ; un ratio en baisse est rapporté, pas corrigé. Selon Q-H5b-1 (b) : témoin = 0.
6. V6 — à l'œil (utilisateur) : comportement des PNJ en ville après un déplacement et en temps accéléré ; scènes du
joueur et interface inchangées (§ 1, « Ce que l'utilisateur verra »).
Fichiers à commiter (dépôt jeu, branche ue5.8, ticket au gardien) :
- A
Docs/Migration/etat/ST/STE/STE-H5b-SPEC.md
Tours : 48 / 60
Constats
- Établi : nœuds et liens du § 2.2 (EG) ; MD5 et propreté git de
GI.uasset(commandes en tête) ; condition deMacroInstance_45(5 termes, dontNot(SceneOn)etLen(followUp) == 0) ;.lpaiexécutés dansPlayScenepar uneWhileLoopsans suspension pour le contenu actuel ; flux de données d'AddVariableet deAsyncen 5.5 (L6f) ; comptes rejoués sur L2 et L3 (ci-dessous). - Estimé : sémantique d'exécution d'
AddVariable(A1-A3, P3) ; nom d'objetAIdeAIDummy; réévaluation des nœuds purs ; absence de ligne lourde dansrandom.lpai:10(la seule correspondance degenerate|dressdans les.lpaiavec le motif large est une liste de lieux,beauty.lpai:12contienthairdresser). - Incertain : écrivain de
GI.AIDummy(hors GI, non cherché dans les autres Blueprints : aucun dump) ; sortie exacte d'Asyncquand la condition devient fausse (utile à F-b seulement). - Comptes (Grep, mode
count) : L2Add Variable|via AddVariable|DestroyDummy was from AddVariable→ 0 ; L2hours by|WHO unmatched|index SPAWN→ 339 (lecture du fichier vérifiée) ; L2LogBlueprintUserMessages: \[AI\]→ 9 ; L3 même motif → 48 ; L3via AddVariable|DestroyDummy was from AddVariable| Add Variable→ 6 ; L3WHO unmatched→ 106 ; L3hours by [1-9]→ 46 ;Content\Modules: 17.lpai(Glob),AI.dans*.lpai→ 95, dans*.lpscene→ 0,^\s*AI\s*=→ 0. - Dumps 5.8 manquants :
AddVariable(P3, bloquant),Async(facultatif),GetVariable(non nécessaire : F-a n'en dépend pas ; flux 5.5 en L6f:10274). Aucun dump 5.8 n'a de broches d'exécution pour ces graphes (Glob**/*AddVariable*,**/*Async*sousetat\: 0 ; seul L6f les contient, sans-Exec). - Écart à la fiche : aucun. Point (b) traité par P3 (préalable bloquant) plutôt que par un arrêt de la SPEC, parce que
l'appel ajouté est identique à
CallFunction_739, déjà exécuté à chaque PNJ.