Fiche STF-T4 — Niveau N1 — Modèle prévu sonnet | utilisé claude-sonnet-5-5 — Agent lp-validator — Skills sk-protocol, sk-recount, debug-verification, lp-validate # STF-VAL : validation du lot STF, partie statique puis VAL finale (2026-10-10) Copie `D:\Game\LifePlay-master 5.8`, branche `ue5.8`. `STF-avant` = tag annoté (objet `8ede633`) sur le commit `b63196a` (relu à la VAL finale, inchangé) ; HEAD à la VAL finale : `2cca224` (d'autres lots ont commité depuis : sans effet sur `Content`). Validateur sans éditeur, sans commandlet, sans build, sans MCP, sans écriture dans `Content` / `Config` / `Source`, sans git en écriture. Seul fichier écrit : ce livrable (deux passes : partie statique sur MainMenu `39135bcd…`, puis VAL finale sur MainMenu `00e42d72…` après T3b et la partie dynamique de `STF-T4-PIE.md`). Horodatages : les journaux d'éditeur sont en UTC ; l'heure locale (noms de fichiers, `ls`) est UTC + 2 h. Les heures « 09:37:59 », « 10:09:04 », « 10:19:05 » de la fiche sont donc des heures de journal (UTC). Méthode d'analyse binaire : les `.uasset` (avant = `git show STF-avant:Content/UI/MainMenu.uasset`, copiée dans le scratchpad hors dépôt ; après = copie du fichier de la copie UE) sont lus par un analyseur Python écrit pour la session (scratchpad, non versionné : `count.py`, `pkg2.py`, `entry.py`, `idx.py`, `events.py`, `diffexp.py`, `links.py`, `props.py`, `edges.py`, `newnames.py`). Il lit l'en-tête du paquet : table des noms (1217 avant, 1215 à T3, **1219** final), table des exports (1686 avant, 1722 à T3 et final), exports **contigus de bout en bout**, fin du dernier export = taille du fichier moins 52 octets dans les trois états : ce qui valide le décodage. Scripts à ranger dans `Saved/STF/` si l'orchestrateur veut les rejouer (§ 6, case 4). ## 1. Fiches amont relues Relues en entier à la partie statique : `STF-SPEC.md` (§ 0-6), `STF-T1-CART.md`, `STF-T3-IMPL.md`, `STF-TACHES.md`. Relues à la VAL finale : `STF-T4-PIE.md` (§ 1-6, en entier), `STF-SPEC.md` § 7 (E1 à E4), `STF-T3-IMPL.md` § 2 (correction des événements 38 et 41 vérifiée : l. 50 « déjà pris (délégués `OnClicked` de boutons, avant et après STF) », conforme à ce que j'avais relevé). `STF-T0-CART.md` non relu (cité par T1 / T3). Instantané : `D:\Game\LifePlay_Backup_5.5\STF\manifest.csv` (3 lignes : MainMenu 59D1EE71…, GameSettings.sav 590B2CC5…, Default.sav 81F13C39…, 11:04) et ses 3 copies. Écarts de forme (gabarits `lp-doc`), sans effet sur le fond : `STF-T3-IMPL.md` n'a pas les sections IMPL numérotées 3 à 6 ni la ligne `Tours` ; `STF-T1-CART.md` n'a pas les sections CART 4 à 6 ni `Tours` ; `STF-T4-PIE.md` n'a pas de sections numérotées de gabarit (c'est un relevé, non un rôle du gabarit) ni de ligne `Tours`. ## 2. Points à confirmer des IMPL | # | Point (source) | Verdict | Preuve | |---|---|---|---| | P1 | MD5 avant / après T3 et GI inchangé (T3 tableau initial) | PASS | § 3 C1 ; état final § 3 F1 | | P2 | `git status -- Content Config Source` = MainMenu seul | PASS (rejoué à la VAL finale) | § 3 C1, F5 | | P3 | Anciens noms 0, ShadeDepth 2, neufs 5, témoins 5 / 5 / 6 (T3 § 4, « estimé ») | PASS (recompté, état T3 puis état final) | C2a, F1 | | P4 | « 0 liaison vers GI sur les 12 » (T3 § 4) | PASS-STATIC → établi sur l'asset final (fichier, pas moteur) | C2b-C2c, F1 | | P5 | 14 `OnValueCommitted` + 1 `OnValueChanged` (SliderCameraSpeed) (T3 § 4) | PASS-STATIC (état T3 et final) | C3, F1 | | P6 | Écart E1 : chaînes `IsValid → Set` gardées | PASS-STATIC (niveau nœud) ; confirmé en jeu par S1 (V5) | C4, F1, F6 | | P7 | Écart E2 : SquirtMult `IsValid` fonction + Branche | PASS-STATIC (niveau nœud) ; SquirtMult tapé 4 → GI 4 en S1 | C4, F1, F6 | | P8 | `Construct` : 12 `SetValue` chaînés (T3 § 3) | PASS-STATIC (niveau nœud) ; champs = GI à M0 (12 / 12) | C3b, F1, F6 | | P9 | 34 propriétés recopiées « 0 écart » (T3 § 2) | reporté : relues seulement pour les 3 widgets T3b (F3) ; les 9 autres ne sont pas relues octet à octet | — | | P10 | `compile_blueprint`, `hyper_diagnose`, journal éditeur (T3 § 4) | reporté pour `hyper_diagnose` et le journal T3 (non rejouables) ; compilation couverte par V1 (F4) | F4 | | P11 | `CompileAllBlueprints` 418 / 418 (T3 § 4 « reporté en T4 ») | **PASS** (journal recompté) | F4 | | P12 | V4-V7, J1 (PIE, utilisateur) | V4 à V7 : voir F6 (PASS ou PASS avec réserve) ; J1 : à faire par l'utilisateur | F6 | | P13 | V8 (`.sav`) | **PASS final** | F5 | | P14 | E3 (arrondi entier, T3b) : 3 SpinBox, Delta 1, snap, 0 décimale, SceneFreq Min / MinSlider 1 | PASS-STATIC : propriétés relues dans l'asset final | F3 | | P15 | Incident de fermeture de l'éditeur (T4-PIE § 4) | constaté dans les journaux ; aucune écriture perdue | F7 | ## 3. Critères rejoués (commande → compte brut) ### 3.A Partie statique (état T3, MainMenu `39135bcd…`) — résultats du 2026-10-10 matin, conservés #### C1 — État de la copie : **PASS** | Commande | Résultat brut | |---|---| | `git status --short -- Content Config Source` | 1 ligne : ` M Content/UI/MainMenu.uasset` | | `md5sum Content/BPs/GI.uasset` | `d93785fca90e3342575fc0b601cc2e93` | | `md5sum Content/UI/MainMenu.uasset` (alors) | `39135bcd5a13167a507e6b5059efbeb0`, 2 245 641 o | | `md5sum D:/Game/LifePlay_Backup_5.5/STF/Content/UI/MainMenu.uasset` | `59d1ee7190afb88bf51b90eda26fcc32` | | `git show STF-avant:Content/UI/MainMenu.uasset \| md5sum` | `59d1ee7190afb88bf51b90eda26fcc32` (= instantané) | | `git show STF-avant:Content/BPs/GI.uasset \| md5sum` | `d93785fca90e3342575fc0b601cc2e93` (= actuel) | | `git cat-file -t STF-avant` ; `git rev-parse "STF-avant^{commit}"` | `tag` ; `b63196a579ec46e4e44b2ac99391b4367550f5bf` | #### C2 — V2, liaisons : **PASS** **C2a — décompte** (NUL final, non précédé de `[A-Za-z0-9_]` ; `python -I count.py MainMenu_avant.uasset `) : | Nom | Avant | T3 | Final | | Nom | Avant | T3 | Final | |---|---|---|---|---|---|---|---|---| | ChildGrowthMult | 7 | 0 | 0 | | SpinBoxChildGrowth | 0 | 5 | 5 | | ShadeDepth | 8 | **2** | **2** | | SpinBoxShadeDepth | 0 | 5 | 5 | | SpinBoxBGA | 7 | 0 | 0 | | SpinBoxVolBGA | 0 | 5 | 5 | | SpinBoxMarkerSize | 7 | 0 | 0 | | SpinBoxMapMarkerSize | 0 | 5 | 5 | | SpinBoxMoan | 7 | 0 | 0 | | SpinBoxVolMoan | 0 | 5 | 5 | | SpinBoxPhysicsMult | 7 | 0 | 0 | | SpinBoxPhysics | 0 | 5 | 5 | | SpinBoxSceneFrequency | 7 | 0 | 0 | | SpinBoxSceneFreq | 0 | 5 | 5 | | SpinBoxSexDescription | 7 | 0 | 0 | | SpinBoxSexLineDuration | 0 | 5 | 5 | | SpinBoxSex | 7 | 0 | 0 | | SpinBoxVolSex | 0 | 5 | 5 | | SpinBoxSquirtMult | 7 | 0 | 0 | | SpinBoxSquirt | 0 | 5 | 5 | | SpinBoxUI | 7 | 0 | 0 | | SpinBoxVolUI | 0 | 5 | 5 | | SpinBoxPregnancyTerm | 7 | 0 | 0 | | SpinBoxPregnancyMult | 0 | 5 | 5 | | **Témoins** SpinBoxSexDuration | 5 | 5 | 5 | | SliderCameraSpeed | 5 | 5 | 5 | | SpinBox_0 | 6 | 6 | 6 | | | | | | Localisation (`pkg2.py `), `ChildGrowthMult` avant : 7 = table des noms (1) + export `SpinBox` dans `WidgetTree` (2) + export `MainMenu` (WidgetBlueprint) à +4154 et +93319 (2) + export `MainMenu_C` à +2869 et +29227 (2). Le témoin `SpinBoxSexDuration` n'a que +49710 (WB) et +20220 (classe) : l'écart de 2 = **une entrée de liaison éditeur + une entrée de liaison exécution** (établi par position ; T1 § 4 ne l'avait qu'« estimé »). `ShadeDepth` après (2) = table des noms (1) + littéral du nœud `K2Node_CallFunction_820` (paramètre matériau, 1). **C2b — tableaux de liaisons** (`python entry.py MainMenu|MainMenu_C 0 ` : FString `ObjectName` suivie de la balise `PropertyName`) : | Tableau | Avant | T3 | Final | Disparues | |---|---|---|---|---| | éditeur (`MainMenu`, WidgetBlueprint) | 31 | 19 | 19 | exactement les 12 anciens widgets | | exécution (`MainMenu_C`) | 31 | 19 | 19 | idem | Avant : les 12 entrées lisaient `Value ← ` : SceneFrequency→SceneFrequency, SexDescription→SexLineDuration, PregnancyTerm→PregnancyMultiplier, ShadeDepth→ShadeDepth, ChildGrowthMult→ChildGrowthMultiplier, MarkerSize→MarkerSize, PhysicsMult→PhysicsMult, BGA→Vol_BGA, UI→Vol_UI, Sex→Vol_Sex, Moan→Vol_Moan, SquirtMult→SquirtMult. Après : 18 entrées hors SpinBox (boutons, textes, `CanvasPanel_33`, `Version`…, inchangées) + **`SpinBox_0` (`Value ← Get_SpinBox_0_Value_0`, fonction)**, seule liaison SpinBox restante (SPEC § 3). **C2c — variables GI** (`python idx.py`, indice de nom, tous alignements, fenêtres des tableaux) : les 12 variables (ChildGrowthMultiplier, ShadeDepth, Vol_BGA, MarkerSize, Vol_Moan, PhysicsMult, SceneFrequency, SexLineDuration, Vol_Sex, SquirtMult, Vol_UI, PregnancyMultiplier) : **avant 2 (éditeur) / 1 (exécution) chacune ; après 0 / 0** (témoin positif : l'avant les trouve). Aucune entrée ne référence un ancien nom ni une variable GI des 12. #### C3 — V3, événements : **PASS-STATIC (partiel)** `python events.py ` (exports `K2Node_ComponentBoundEvent`, FName `DelegatePropertyName` / `ComponentPropertyName`) : | | Avant | T3 | Final | |---|---|---|---| | nœuds `ComponentBoundEvent` | 48 | 47 | 47 | | `OnValueChanged` | 13 (12 + `SliderCameraSpeed`) | 1 (`SliderCameraSpeed`, `_30`) | 1 | | `OnValueCommitted` | 3 (`_19` SpinBox_0, `_15` MarkerSize, `_31` SexDuration) | 14 | 14 | Les 12 événements neufs : `_32` ChildGrowth, `_33` ShadeDepth, `_34` VolBGA, `_35` MapMarkerSize, `_36` VolMoan, `_37` Physics, `_39` SceneFreq, `_40` SexLineDuration, `_43` VolSex, `_44` VolUI, `_45` PregnancyMult, `_46` Squirt (tous `OnValueCommitted`). `_19` (SpinBox_0, FName « SpinBox » + suffixe) n'est pas rattaché par mon filtre ; relu à part : composant `SpinBox_0`, délégué `OnValueCommitted`, inchangé. T3 § 2 (« 38, 41, 42 sans nœud ») était inexact pour 38 et 41 (`OnClicked`, boutons, présents avant et après) : **corrigé par l'orchestrateur, vérifié**. **C3b — `Construct`** : voir F1 (43 liens attendus, 43 présents ; ancien lien `_73 ↔ _1278` absent). #### C4 — Relecture critique T3 contre la SPEC : **PASS-STATIC**, E1 et E2 sans effet sur C4, V3, V7 Diff d'exports (`python diffexp.py` ; 1686 → 1722 exports, clés (nom, classe) distinctes 881 → 917 ; 39 retirés, 75 ajoutés, +36) : - retirés (39) : 12 `SpinBox` anciens, 13 `K2Node_ComponentBoundEvent` (`_6, _13, _15, _17, _20, _21, _22, _23, _26, _42, _84, _118, _178`), 13 fonctions `BndEvt__…`, `ComponentDelegateBinding_4` ; - ajoutés (75) : 12 `SpinBox`, 12 événements, 12 `BndEvt__MainMenu_…Committed…`, `ComponentDelegateBinding_13`, 13 `K2Node_CallFunction` (`_78` IsValid + 12 `SetValue`), `K2Node_IfThenElse_9`, 24 `K2Node_VariableGet` ; - **aucun** `K2Node_VariableSet` / `K2Node_MacroInstance` créé ou supprimé, aucun `VariableGet` supprimé : « chaînes gardées » et « nœuds GI partagés intacts » (T3 § 1). Le même diff, rejoué sur l'asset final (avant → final), donne exactement les mêmes totaux (881 → 917 ; 39 / 75 ; mêmes classes). - **E1 (chaînes gardées)** : graphe obtenu = celui de la SPEC ; C4 inchangé, V3 tenu. **E2 (SquirtMult, fonction `IsValid` + Branche)** : équivalent à la macro. Réserve inchangée : sorties de `IfThenElse_9` vérifiées au niveau nœud seulement. #### C5 — V8 provisoire (T3) : PASS. Remplacé par F5 (V8 final). ### 3.B Partie dynamique et VAL finale (asset final `00e42d72c773a55f6998ae67662fdb76`, 2 246 412 o) #### F1 — V2 et V3 sur l'asset final : **PASS** (V2 établi sur fichier) / **PASS-STATIC** (V3) `md5sum Content/UI/MainMenu.uasset` = `00e42d72c773a55f6998ae67662fdb76` (copie du fichier = `MainMenu_final.uasset` dans le scratchpad, même MD5), mtime 12:14 locale = sauvegarde du journal T3b (`LogFileHelpers: Saving Package: /Game/UI/MainMenu`, 10:14:13 UTC, T3b log l. 2371). - **V2** : `count.py` (colonne « Final » de C2a) : 12 anciens à 0 (ShadeDepth 2), 12 neufs à 5, témoins 5 / 5 / 6. `entry.py` : tableaux de liaisons éditeur **19**, exécution **19** (31 avant) ; seule liaison SpinBox restante : `SpinBox_0` (Function). `idx.py` (fenêtres 0-11086 éditeur, 0-8253 exécution, indices de noms du fichier final) : les 12 variables GI : **0** occurrence dans les deux fenêtres (24 comptes à 0 sur 24). Réponse : aucune entrée de liaison ne référence un ancien nom ni une variable GI des 12. - **V3** : `events.py` : 47 `ComponentBoundEvent`, **14 `OnValueCommitted`, 1 `OnValueChanged` (SliderCameraSpeed)**, aucun `OnValueChanged` de SpinBox. `edges.py` (références croisées nœud à nœud, chaînes de T3 § 2 et § 3) : **43 liens attendus, 43 présents** (12 chaînes d'événements : 2 + 4 + 2 + 4 + 2 + 2 + 2 + 2 + 2 + 2 + 2 + 4 liens ; `Construct` `_73 → _79 → … → _92 → _1278` : 13) ; l'ancien lien `CallFunction_73 ↔ CallFunction_1278` : **absent** (False). Niveau nœud, estimé pour l'équivalence de comportement ; le broche à broche n'est pas relu ici. - Bruit : `links.py` (recherche libre des voisins) devient bruyant sur l'asset final parce que l'insertion de 4 noms décale tous les indices de noms ; `edges.py` ne teste que les liens attendus et n'est pas touché par ce bruit. #### F2 — Écart 39135bcd → 00e42d72 : **limité aux propriétés des 3 SpinBox (estimé fort, bilan chiffré)** Je n'ai pas de copie de `39135bcd…` (non commitée, absente de l'instantané) : le bilan est arithmétique, pas un diff octet à octet. | Grandeur | 39135bcd (relevé matin) | 00e42d72 | Différence | |---|---|---|---| | taille du fichier | 2 245 641 | 2 246 412 | **+771** | | nombre d'exports | 1722 | 1722 | 0 | | entrées de liaisons éditeur / exécution | 19 / 19 | 19 / 19 | 0 | | événements `OnValueCommitted` / `OnValueChanged` | 14 / 1 | 14 / 1 | 0 | | noms (table) | 1215 | 1219 | +4 | | en-tête (`TotalHeaderSize`) | 783 237 | 783 336 | **+99** | | données des exports (fin du dernier export − début) | 1 462 352 | 1 463 024 | **+672** | - Les 4 noms nouveaux sont `Delta` (indice 374), `bAlwaysUsesDeltaSnap` (84), `MinFractionalDigits` (703), `MaxFractionalDigits` (691) ; absents de la table avant STF (`newnames.py`). Leur coût en table (FString + 4 octets de hachage) : 14 + 29 + 28 + 28 = **99 octets** = l'écart d'en-tête. - Exactement **6 exports** contiennent l'un de ces 4 noms (`newnames.py`) : `SpinBoxSceneFreq` #1492 et #1506, `SpinBoxMapMarkerSize` #1489 et #1503, `SpinBoxSexLineDuration` #1494 et #1508, soit 3 widgets × 2 exports (copie d'archétype et instance), chacun avec les 4 propriétés. Une balise = 29 (Delta) + 29 (MinFractionalDigits) + 29 (MaxFractionalDigits) + 25 (bAlwaysUsesDeltaSnap) = **112 octets**, × 6 = **672 octets** = l'écart de données des exports. - 99 + 672 = **771** = l'écart de taille du fichier, à l'octet. Autant d'exports, autant d'entrées de liaisons, mêmes décomptes d'événements : rien d'autre n'a bougé en taille. Limite : un changement de valeur de même taille (p. ex. `MinValue` 0.2 → 1.0 sur `SpinBoxSceneFreq`) est invisible à ce bilan ; il est relu en F3. #### F3 — Valeurs relues dans l'asset final : **PASS-STATIC (établi sur fichier)** `python props.py MainMenu_final.uasset SpinBoxSceneFreq SpinBoxMapMarkerSize SpinBoxSexLineDuration` : balises de propriété lues (type float / int / bool, valeur dans l'octet suivant la balise), identiques dans les deux exports de chaque widget : | Widget | Value | MinValue | MaxValue | MinSliderValue | MaxSliderValue | Delta | bAlwaysUsesDeltaSnap | Min / MaxFractionalDigits | |---|---|---|---|---|---|---|---|---| | SpinBoxSceneFreq | 10 | **1.0** | 100 | **1.0** | 100 | **1.0** | **true** | **0 / 0** | | SpinBoxMapMarkerSize | 28 | 1.0 | 100 | 1.0 | 100 | **1.0** | **true** | **0 / 0** | | SpinBoxSexLineDuration | 15 | 1.0 | 100 | 1.0 | 100 | **1.0** | **true** | **0 / 0** | Conforme à E3 (STF-SPEC § 7) et à STF-T4-PIE § 4. Valeurs = défauts GI (10, 28, 15) ; bornes Max inchangées. Les 4 `bOverride_Min/Max(Slider)Value` restent à vrai. Témoin : `SpinBoxVolBGA` (non modifié) ne porte ni Delta, ni chiffres, ni `bAlwaysUsesDeltaSnap` (valeurs par défaut du moteur). Le comportement à l'exécution (arrondi 33.6 → 34, 0 → 1) n'est pas rejouable ici (voir F6). #### F4 — V1, `CompileAllBlueprints` : **PASS** Journal `Saved\Logs\portage\STF_CompileAllBlueprints_20261010-122113.log` (482 121 o, ouvert 12:21:14, après la sauvegarde de l'asset final à 12:14 : il compile bien `00e42d72…`) : | Commande | Compte brut | |---|---| | `grep -c 'Loading and Compiling'` | **418** | | `grep -c 'a réussi'` | **418** | | `grep -c 'échoué'` | 0 | | `grep -c 'Error:'` | 0 | | `grep -n 'Compiling Completed'` | l. 3234 : `Compiling Completed with 0 errors and 0 warnings and 0 blueprints that failed to load.` | | `grep -n 'Success -'` | l. 3241 : `LogInit: Display: Success - 0 error(s), 0 warning(s)` | | ligne MainMenu | l. 2800 `Loading and Compiling: '/Game/UI/MainMenu.MainMenu'` ; l. 2802 `[0120,51] La compilation de MainMenu a réussi ! [en 443 ms]` | Lecture de l'orchestrateur (418 / 418 / 0 / « 0 error(s), 0 warning(s) ») **confirmée**. Mon premier décompte large (`échec|failed`, 12 lignes) ne compte que des messages d'environnement sans lien avec les Blueprints (DLL absentes `aqProf` / `VtuneApi` / `WinPixGpuCapturer`, SDK Android / IOS / Linux / Mac / TVOS non installés) ; aucun n'est un échec de compilation. Résumé : `etat\ST\STF\STF_CompileAllBlueprints_20261010-122113.txt` (présent, 133 894 o ; non relu ligne à ligne). Exécution du commandlet par l'orchestrateur : non rejouée (interdit ici). #### F5 — V8 final et état des fichiers : **PASS** | Fichier | MD5 actuel (`md5sum`) | Référence | Verdict | |---|---|---|---| | `Saved/SaveGames/GameSettings.sav` | `590b2cc503344f5b76971517b1de098e` (3 752 o, 2026-10-08 17:20) | instantané `590B2CC5…` | identique | | `Saved/SaveGames/Default.sav` | `81f13c39eaf5dde64981fae83b1ef70a` (100 676 o, 2026-10-08 17:20) | instantané `81F13C39…` | identique | | `Saved/Config/WindowsEditor/GameUserSettings.ini` | `6f25ef005641f54d313cc76c7b9491fc` (1 585 o, mtime 09:59 locale) | entrée 6f25ef00… à 11:33 | identique, non touché depuis | | `Content/BPs/GI.uasset` | `d93785fca90e3342575fc0b601cc2e93` | T1, T3 | inchangé | `git status --short -- Content Config Source` : ` M Content/UI/MainMenu.uasset` seul ; `git diff --stat STF-avant -- Content Config Source` : 1 fichier, `Bin 2171521 -> 2246412 bytes`. #### F6 — V4 à V7 : relevés de `STF-T4-PIE.md`, niveaux de preuve et contre-vérifications des journaux Niveaux : **établi-orch** = relevé MCP (`ObjectTools.get_properties` sur `GI_C_0` et les SpinBox) par l'orchestrateur, **non rejouable sans éditeur** ; **déclaré** = dit par l'utilisateur ; **journal** = rejoué par moi dans le journal. | Critère | Attendu (SPEC § 5) | Relevé (STF-T4-PIE) | Niveau | Verdict | |---|---|---|---|---| | V4 | PIE M0-M6 : 0 écart sur les 14 variables | M0 : 12 = défauts, CameraSpeed 4, SexDurationMult 2, champs = GI (12 / 12) ; S1, S2 : GI = champs ; M2 (partie lancée, `MainMenu_C_1` recréé) : champs = GI (12 / 12) ; M3-M5 (`_C_2`) inchangé ; S4 (`_C_3`) : SceneFrequency 33 gardée, 13 autres inchangées. **9 variables reviennent au défaut à M2** (§ 2 : `LoadSettings`) | établi-orch | **PASS avec réserve** : 0 écart champ / GI à chaque point relevé, mais (a) les 9 retours au défaut sont un comportement d'origine de `LoadSettings`, jugé hors STF (cause « estimée » : classe `GameSettings` non relue), (b) les points M1 et M6 ne sont pas libellés dans le relevé | | V5 | 12 valeurs tapées + Entrée : GI = valeur ; menu fermé puis rouvert : champ = valeur, GI inchangé | S1 : 12 / 12 (2, 0.7, 1.5, 40, 2, 3, 20, 25, 2, 4, 2, 1.5), `ShadeDepth` 0.69999999 = 0.7 en float ; S2 : champs = GI | établi-orch (sur l'asset 39135bcd) | **PASS** pour les 12 à T3. Après T3b : 33.6 → 34 (MapMarkerSize) et 0 → 1 (SceneFreq) tapés **déclarés** par l'utilisateur, **sans relevé MCP** (PIE arrêté avant) : PASS déclaré | | V6 | glisser (SceneFreq) : GI mis à jour en fin de geste, affichage fluide | S3 : SceneFrequency 35.1685… = champ après relâchement | établi-orch pour la valeur de fin ; affichage « fluide » / « en entiers pendant le glisser » après T3b : **déclaré** | **PASS avec réserve** : GI = champ après le geste établi ; l'absence d'écriture de GI pendant le geste n'a pas été relevée (état intermédiaire non lu) | | V7 | `GI.MarkerSize` = valeur, `SpawnMapMarkers` appelé 2 s après | S1 : MarkerSize 40 = GI ; `SpawnMapMarkers` exécuté vers 09:37:59 | établi-orch (valeur) ; **journal** (appel) | **PASS avec réserve** : voir ci-dessous, l'appel est établi par ses effets (erreurs StreetMap), le délai de 2 s n'est pas recompté | | V1 | (F4) | 418 / 418 / 0 | journal | **PASS** | | V2 | (F1) | 0 liaison Property vers GI sur les 12 | fichier | **PASS** | | V3 | (F1) | plus aucun `OnValueChanged` des 12 ; 12 `OnValueCommitted` | fichier | **PASS-STATIC** (partiel : liens broche à broche non relus ; en jeu, S1 prouve que chaque `Set` part du commit : GI = valeur tapée 12 / 12) | | V8 | (F5) | MD5 des `.sav` = instantané | commande | **PASS** | **Contre-vérifications des journaux** (`grep` sur `Saved\Logs\portage`, heures UTC) : | Élément cité | Journal | Résultat brut | |---|---|---| | `SpawnMapMarkers` vers 09:37:59 | `STF-T4_PIE_20261010-113347.log` | **0** occurrence de la chaîne « SpawnMapMarkers » (l'appel de fonction Blueprint ne s'écrit pas au journal). Mais à `[2026.10.10-09.37.59:488-489]` (frame 310) : 4 `PIE: Error` « lecture de la propriété StreetMap dans /Game/BPs/StreetMap_Static » + « Accès à None » avec `Fonction : Execute Ubergraph Map Markers` (ForEachLoop) et `Execute Ubergraph GI`. Établi : les graphes de marqueurs de carte ont tourné à 09:37:59 ; **estimé** : c'est `SpawnMapMarkers` déclenché par la validation de Map Marker Size (aucun appel de log direct). Heure de la validation et délai de 2 s : non lisibles | | erreurs `StreetMap` (écran titre, hors périmètre) | idem | 16 lignes contenant « StreetMap » ; erreurs d'exécution à 09:34:54.561-.562 (`StreetMapStatic`, init GI) et 09:37:59.489 (`StreetMap`) : confirmées | | `SpinBox_0` : 12 « Accès à None » | idem | 94 lignes `PIE: Error` au total ; **12** `PIE: Error` « propriété GI dans /Game/UI/MainMenu.MainMenu_C » et **60** lignes citant `Get_SpinBox_0_Value_0` (dès 09:34:54.611, initialisation du menu) : confirmé, widget et liaison non touchés par STF | | ShadeDepth : `Cast failed` | idem | **1** ligne `LogBlueprintUserMessages: [MainMenu_C_0] Cast failed` à 09:37:26.980 : confirmé (chaîne d'origine, `PrintString`) | | PIE T4 arrêté / éditeur fermé | idem | `Shutting down PIE online subsystems` 10:08:55.406 ; `LogExit: Exiting.` 10:09:04.989 ; `Log file closed 12:09:05` locale : confirmé ; aucune ligne `Fatal error` / `Assertion failed` / `Unhandled` (recherche faite, 0) | | relance de l'éditeur, sauvegarde | `STF-T3b_Editor_20261010-121244.log` | ouvert 12:12:45 locale ; `Saving Package: /Game/UI/MainMenu` 10:14:13.606 UTC, déplacement du `.tmp` vers `Content/UI/MainMenu.uasset` 10:14:14 : confirmé | | arrêt du PIE de contrôle | idem | PIE créé 10:17:05.816 (CentralLondon) ; `Shutting down PIE online subsystems` **10:19:05.272** : confirmé (2 min) ; 0 `Fatal` / `Assertion` ; 27 lignes `PIE: Error` dont 15 sur MainMenu / SpinBox (`Get_SpinBox_0_Value_0`, init, comme au T4) ; aucun `Cast failed` ni ShadeDepth dans ce journal (ShadeDepth non validé pendant le contrôle) | Les valeurs de `GI` (relevés MCP) et les champs ne figurent dans aucun journal : **non contre-vérifiables**, établi par l'orchestrateur seulement. #### F7 — Incident de fermeture de l'éditeur (demande de Big Boss) et écarts E1 à E4 de STF-SPEC § 7 **Incident** (STF-T4-PIE § 4, journaux relus en F6) : à la fin de l'essai PIE de la partie dynamique, l'utilisateur a **fermé l'éditeur** (sortie `LogExit: Exiting.` à 10:09:04 UTC, après `Shutting down PIE online subsystems` à 10:08:55) au lieu d'arrêter seulement le PIE. Conséquence : arrêt de la session MCP et relance de l'éditeur à 10:12 UTC (`STF-T3b_Editor_20261010-121244.log`). Aucune écriture perdue : MainMenu n'était pas encore modifié par T3b (sauvegarde à 10:14:13 UTC, postérieure). Sortie propre (pas de plantage dans le journal). Un appel MCP signalé « session expired » par le client avait été exécuté ; le second a écrit les mêmes valeurs (sans effet cumulatif, déclaré par l'orchestrateur, non vérifiable au journal). Classement : incident d'exploitation, **sans effet sur l'asset final** (F1-F3 relus sur `00e42d72…`). **Écarts de STF-SPEC § 7** (avis du validateur ; la décision revient à l'utilisateur) : | # | Écart | Validé ? | Avis | |---|---|---|---| | E1 | chaînes `IsValid → Set` gardées et rebranchées (au lieu d'être recréées) | PASS-STATIC (C4, F1) | sans effet sur C4 / V3 ; confirmé en jeu par S1 | | E2 | SquirtMult : `IsValid` fonction + Branche au lieu de la macro | PASS-STATIC (C4, F1) | sans effet ; SquirtMult tapé 4 → GI 4 en S1 | | E3 | arrondi entier (T3b) sur SceneFreq, MapMarkerSize, SexLineDuration ; SceneFreq Min / MinSlider 0.2 → 1 | propriétés relues (F3), PASS-STATIC ; comportement en jeu **déclaré** | dérogation à C2 (bornes inchangées) et C4 pour ces 3 champs, **décision de l'utilisateur** consignée en SPEC § 7. Risque noté : une valeur non entière déjà présente dans `GameSettings.sav` ou dans GI (p. ex. SceneFrequency 35.1685 vu en S3) est **affichée** arrondie par `SetValue` sans être réécrite avant validation du champ (SPEC § 6) — estimé | | E4 | J1 : `LoadSettings` recharge 9 des 12 réglages, pas 2 | constat T4-PIE § 2 (cause **estimée**) | J1 reformulé ci-dessous ; comportement d'origine, hors périmètre | ## 4. Diff lu en entier `git diff --stat STF-avant` sur `Content Config Source` : **1 fichier**, binaire (`Content/UI/MainMenu.uasset`, 2 171 521 → 2 246 412 o). Aucun diff texte à lire ; le « diff » est le diff d'exports de C4 (39 retirés / 75 ajoutés, tous annoncés par T3, aucun type de nœud inattendu) complété par F2 (écart T3 → final = 4 noms et 6 exports de 112 octets). Autres fichiers modifiés par les lots voisins (`.gitignore`, `Docs/…`, `Tools/…`) : hors périmètre STF, non relus. Fins de ligne : sans objet pour le `.uasset`. ## 5. Verdict **Verdict global : PASS avec réserve** (VAL finale du 2026-10-10). - PASS : V1 (418 / 418 / 0 / 0), V2 (fichier), V8 (3 MD5 identiques), C1 (état), E1 et E2 (sans effet). - PASS-STATIC : V3 (niveau nœud et en jeu par S1), propriétés E3 (fichier). - PASS avec réserve : V4 (M1 et M6 non libellés ; 9 retours au défaut = comportement d'origine de `LoadSettings`, cause estimée), V6 (écriture de GI pendant le geste non relevée ; affichage entier déclaré par l'utilisateur), V7 (appel de `SpawnMapMarkers` établi par ses effets au journal, délai de 2 s non recompté), V5 après T3b (arrondis déclarés, pas de relevé MCP). - Aucun FAIL. **J1 : à faire par l'utilisateur** (non fait, non comptée comme passée). Niveau de preuve : décodage de l'asset sur disque **établi** (exports contigus, trois états cohérents) ; bilan T3 → final **estimé fort** (arithmétique à l'octet, pas de copie de `39135bcd…`) ; équivalence de comportement **estimée** (graphe lu au niveau nœud) ; relevés `GI` / champs : **établi par l'orchestrateur, non rejouable sans éditeur** ; PIE de contrôle T3b : **déclaré par l'utilisateur**. ## 6. Points à confirmer par l'utilisateur - [ ] 1. E1 et E2 (chaînes gardées ; garde SquirtMult en fonction + Branche, à écrire au CHG, règle 4 `lp-mcp`) : avis du validateur oui. - [ ] 2. E3 (arrondi entier, SceneFreq Min 0.2 → 1) : dérogation à C2 / C4 déjà décidée par l'utilisateur ; confirmer qu'elle s'étend bien à tout GameSettings.sav ancien (valeur non entière affichée arrondie). - [ ] 3. **J1, à faire par l'utilisateur (archive Development)**, reformulé selon E4 : (a) les 12 réglages se règlent dans le menu et survivent à fermeture / réouverture du menu (observé en PIE, S2 : à refaire sur l'archive) ; (b) `SceneFrequency`, `SexLineDuration` (et les 7 autres de `LoadSettings` : Vol_BGA, MarkerSize, Vol_Moan, PhysicsMult, Vol_Sex, SquirtMult, Vol_UI) ne survivent à un lancement de partie **que s'ils ont été écrits par `SaveSettings`** (sauvegarde puis relancement) ; (c) ChildGrowth, ShadeDepth, PregnancyMultiplier ne sont **jamais persistés** (comportement d'origine, hors périmètre). - [ ] 4. Faire ranger les scripts d'analyse (`count.py`, `pkg2.py`, `entry.py`, `idx.py`, `events.py`, `diffexp.py`, `links.py`, `props.py`, `edges.py`, `newnames.py`) dans `Saved/STF/` ou `Tools/` (le validateur n'écrit pas hors de son livrable), ou les laisser jetables. - [ ] 5. Corriger les sections manquantes des gabarits (T3-IMPL : 3-6 et `Tours` ; T1-CART : 4-6 et `Tours` ; T4-PIE : `Tours`) — hors périmètre du validateur. - [ ] 6. Réserve V4 : accepter M1 / M6 comme couverts par S1-S4, ou demander un relevé de ces deux points. Tours : 36 / 25 pour la passe statique (budget dépassé : décodage du format du paquet) ; VAL finale : 14 / 25 (total du livrable : 50) ## Constats - Fins de ligne : ce livrable est écrit en LF par l'outil Write (pas de CR) ; la conversion CRLF (`sed 's/\r\?$/\r/'`) demandée est une édition par script du fichier, interdite au validateur (`sk-protocol` § 7) : à faire par l'orchestrateur. - `links.py` (recherche libre des voisins) a du bruit : les indices à valeur courante (p. ex. 1024) donnent de faux voisins (vu : `CallFunction_91` ↔ `ComponentBoundEvent_30`). Les chaînes de C3b / C4 sont confirmées par `edges.py` (43 / 43 sur la liste attendue, en F1), pas par la recherche libre. - La fonction `BndEvt__SpinBox_0_K2Node_ComponentBoundEvent_42_…` supprimée portait le nom `SpinBox_0` (renommage antérieur de l'ancien widget PregnancyTerm) : sans effet, `SpinBox_0` (événement `_19`) est intact. - Les heures des fiches (09:37:59, 10:09:04, 10:19:05) sont des heures de journal UTC ; heure locale = +2 h (12:09, 12:19 : correspondent aux `mtime` des journaux). - `ShadeDepth` : les 2 occurrences restantes sont la table des noms et le littéral du paramètre matériau de `CallFunction_820`, pas une liaison. - Aucune nouveauté non demandée vue en passant. ## 7. Décisions de l'utilisateur sur § 6 (2026-10-10, relevées par l'orchestrateur) - Réserves V4, V6, V7 : **acceptées** (« Oui, acceptées ») ; M1 / M6 couverts par S1-S4. VAL : **acceptée avec réserve**. - E1, E2 : sans effet (avis du validateur, retenu) ; E3 : décidé par l'utilisateur pendant le PIE. - J1 : **plus tard** (« J1 plus tard ») ; le commit STF-R2 attend J1, le lot reste ouvert. - Scripts d'analyse : **rangés dans `Tools/`** (« Ranger dans Tools/ ») sous la forme d'un outil unique `Tools/uasset58.py` (`locate`, `events`, `props`, lecteur d'en-tête UE 5.8 de `pkg2.py`) ; contrôle : redonne 48 / 13 / 3 avant et 47 / 1 / 14 après (`ComponentBoundEvent` total / `OnValueChanged` / `OnValueCommitted`), `SpinBoxSceneFreq` 5 et `SpinBoxSceneFrequency` 0 après, 0 et 7 avant ; les relevés ponctuels (fenêtres d'octets `bind.py`, `diffexp.py`, `links.py`…) restent jetables. - Sections de gabarit manquantes (T1, T3, T4-PIE) : à compléter par l'orchestrateur à la DOC. ## J. Preuve en jeu J1 (archive commune STF + STE, 2026-10-10) Archive `D:\Game\LifePlay_Build_5.8_STF-STE_Development` (`STF-J-BUILD.md`). Parcours `STF-J1.md` fait par l'utilisateur dans la même séance que `STE-J1.md`. **Déclaration de l'utilisateur** (relayée mot pour mot par Big Boss) : « J1 fait, tout est conforme ». Mesures de l'orchestrateur sur l'archive (`Windows\LifePlay\Saved`) : | Mesure | Valeur | Lecture | |---|---|---| | `Logs\LifePlay.log` | 1 session (ouverte 13:01:07, dernière écriture 13:14) | le relancement de J1.7 n'est pas dans ce journal (écrasé à chaque lancement) : J1.7 **déclaré** | | erreurs d'exécution Blueprint / `Fatal` | 0 / 0 | aucune erreur Blueprint au journal de la dernière session | | mentions des 12 SpinBox neuves | 0 chacune | aucun message portant sur les widgets STF | | `Get_SpinBox_0_Value_0` / `StreetMap` / « Cast failed » | 240 / 130 / 0 | constats hors périmètre connus (`STF-T4-PIE.md` § 3) | | `property TintUI in` / `GetRootComponent_ReturnValue` / `property Companion in` (STE) | 0 / 0 / 0 | critères STE, pour information | | `SaveGames\GameSettings.sav` (13:12, 5 723 o) | MarkerSize **31**, SceneFrequency **18**, SexLineDuration **22**, Vol_BGA 0.5726, Vol_Moan 1.2372, Vol_Sex 1.1069, Vol_UI 1.0808 (CameraSpeed 2, SexDurationMult 1.9757) | réglages écrits par `SaveSettings` avec des valeurs ≠ défaut ; les 3 champs arrondis (E3) sont des **entiers** ; `PhysicsMult` et `SquirtMult` absents du fichier sous ces noms (non lus) | **Verdict J1 : conforme** (déclaré par l'utilisateur ; arrondi et écriture par `SaveSettings` établis sur fichier ; persistance au relancement déclarée). **Résidu connu hors périmètre** (STF-SPEC C3) : 240 « Accessed None » dans `MainMenu_C`, tous dans `Get_SpinBox_0_Value_0` (`SpinBox_0`, flou de champ CharGen, liaison Function lue pendant `SynchronizeProperties` avant que `GI` soit affecté ; lecture `DepthOfFieldFarBlurSize`) ; aucun ne vient des 12 SpinBox traitées (relevé STE, contre-vérifié par Big Boss et par l'orchestrateur). Ne bloque pas le commit ; proposé à l'utilisateur comme lot à part (même méthode que STF).