LifePlay-Revival/Docs/Migration/etat/REL/MAPDL1/MAPDL1-REX-2026-10-22.md
2026-10-22 21:10:39 +02:00

16 KiB
Raw Blame History

Fiche MAPDL1-REX-2026-10-22 — Niveau N2 — Modèle prévu opus medium | utilisé claude-opus-5-5 — Agent session « Medium · MAPDL1 » — Skills sk-protocol, lp-lot, lp-city

MAPDL1 : retour d'expérience pour les skills et les agents (2026-10-22)

Demande de l'utilisateur, citée mot pour mot par Big Boss : « je souhaite aussi leur retour d'expérience pour enrichir les skills et agents ».

Cette fiche ne touche ni les skills ni les agents : Big Boss les posera après l'accord de l'utilisateur.

Chaque leçon donne quatre choses :

  • Fait : ce qui a été observé, avec sa preuve (fichier:ligne, ou livrable du lot) ;
  • Règle : ce qu'il faut retenir ;
  • Où : le skill et sa section, ou l'agent ;
  • Texte : un texte prêt à coller.

Priorités :

  • P1 : évite une perte de données, une build cassée ou une donnée fausse ;
  • P2 : évite des tours ou des allers-retours ;
  • P3 : confort.

P1

R1. Le Move du moteur supprime la destination

  • Fait : IFileManager::Move(Dest, Src, Replace=true, …) supprime d'abord la destination (Engine/Source/Runtime/Core/Private/HAL/FileManagerGeneric.cpp:303). E5 a donc choisi Move(…, false, false, false, true) (LPCityMapsDownload.cpp:109) pour ne jamais rien supprimer. Vu en relecture, avant tout dégât.
  • Règle : dans un code qui « ne supprime jamais », Replace est toujours false. On écarte d'abord la destination existante par un déplacement horodaté.
  • Où : lp-ue-compat, nouvelle section « API de fichiers » ; rappel dans sk-change-safety.
  • Texte : « IFileManager::Move avec bReplace=true supprime la destination avant de déplacer (FileManagerGeneric.cpp:303). Pour une pose sans suppression : Move(Dest, Src, /*Replace*/false, /*EvenIfReadOnly*/false, /*Attributes*/false, /*bDoNotRetryOrError*/true), après avoir déplacé l'ancienne destination dans un dossier horodaté. Source : MAPDL1-E5. »

R2. OpenSSL dans un module du jeu : conflit de UI

  • Fait : E2 bis a échoué sur une erreur unique, openssl/ossl_typ.h(144,22): error C2365: 'UI' : redéfinition ; la précédente définition était 'espace de noms' (MAPDL1-E2B-BUILD.md). La correction est la parade du moteur, #define UI UI_ST avant les en-têtes et #undef UI après (BuildPatchServices/Private/Common/Crypto.cpp:6-12). E2 ter a ensuite rendu code 0.
  • Règle : on n'inclut jamais openssl/*.h sans cet encadrement. Avant de lancer la build, on cherche par Grep tous les fichiers qui incluent OpenSSL : une seule build doit suffire.
  • Où : lp-ue-compat (ruptures connues) et ue-cpp-build (C2365).
  • Texte : « OpenSSL : #define UI UI_ST / THIRD_PARTY_INCLUDES_START / #include "openssl/evp.h" / THIRD_PARTY_INCLUDES_END / #undef UI. Sans cela : C2365 'UI' (le typedef d'OpenSSL heurte l'espace de noms UI d'UE). Modèle : Engine/Source/Runtime/Online/BuildPatchServices/Private/Common/Crypto.cpp:6-12. »

R3. Height d'un UStreetMap est en centimètres

  • Fait : StreetMap.h:304 annonce des « meters », mais l'import écrit des centimètres (StreetMapFactory.cpp:387). Le GeoJSON de S7 en tient compte : height_m = Height / 100 (MAPDL1-S7-IMPL.md § 2).
  • Règle : toute lecture de FStreetMapBuilding::Height passe en centimètres, quel que soit le commentaire.
  • Où : lp-city § 2, tableau des pièges de géométrie.
  • Texte : « FStreetMapBuilding::Height est en cm, malgré le commentaire « meters » (Public/StreetMap.h:304 ; écrit en cm par StreetMapImporting/StreetMapFactory.cpp:387) | établi, MAPDL1-S7 ».

R4. Une session compile le code posé par une autre

  • Faits :
    • La build de l'éditeur de COM31 a rendu Target is up to date, avec 0 unité. La ligne R-1 avait en effet déjà été compilée à 18:23 par la build de la 1.7.4 de Paris : la DLL de l'éditeur était plus récente que la source (MAPDL1-COM31-BUILD.md). lp-builder y a vu un « échec probable » et s'est arrêté.
    • W1 et W2, posés par MAPDL1 sans être compilés, ont été compilés par le build de la 1.7.7 de STM1 (STM1-155, code 0).
    • MAPDL1 et STM1 se sont échangé leurs listes de fichiers : aucun recouvrement.
  • Règles :
    • (a) Avant d'appeler « échec » un Target is up to date, on compare la date de la DLL ou de l'exe à celle de la dernière source modifiée.
    • (b) Tout code posé non compilé est annoncé aux autres sessions, avec ses MD5 : leur build le compilera, et une casse doit revenir à son auteur.
    • (c) Avant d'écrire dans Source\, chaque session publie sa liste de fichiers et attend le signal de Big Boss.
  • Où : lp-build § 8 pour (a) ; lp-lot/boss.md pour (b) et (c) ; agent lp-builder pour (a).
  • Texte (lp-builder) : « Target is up to date avec 0 unité n'est pas un échec si la DLL ou l'exe est plus récent que la source modifiée : une autre session a déjà compilé. Relève les deux dates (Get-Item), rapporte, et continue la fiche si elle le prévoit. »
  • Texte (boss.md) : « Code posé non compilé : son auteur l'annonce à Big Boss et aux sessions qui compilent (fichiers et MD5). La première build qui le compile rapporte toute erreur à l'auteur. Écriture dans Source\ : liste des fichiers échangée entre les sessions, puis signal de Big Boss. »

R5. Reprise à l'identique d'une ancienne carte UE4

  • Faits :
    • Les cartes « NEW Maps » de Mega sont des UStreetMap UE4 cuits, non versionnés (legacy −7, ue4 = 0, drapeaux 0x80000000), avec des propriétés étiquetées. On les lit hors moteur (LireCarteUE4.py) et on les reprend par réflexion (LPImportLegacyStreetMap, MAPDL1-P1-IMPL).
    • Le maillage LPBuildCityStatic -Flat passe la comparaison avec Londres (1,59 %). Le réglage par défaut et -Unlit échouent (58 %).
    • -Unlit réduit le nombre de sommets, pas celui des triangles.
    • Formule des triangles classiques : 3·Pb − 2·B, écart observé de 0 à −0,18 %.
    • Poids de la 3D classique : environ 20 octets par triangle dans l'archive (MAPDL1-AUTO-FIN § 2).
    • Un asset pilote laissé sous Content\ a cassé la cuisson des packs (DirectoriesToAlwaysCook couvre /Game).
  • Règles :
    • reprise par réflexion, sans conversion ;
    • -Flat pour le maillage statique repris ;
    • aucun asset de travail sous Content\ entre deux sessions ;
    • fourchettes de contrôle tirées de la formule.
  • Où : lp-city, nouvelle section « 9. Reprise d'une ancienne carte LifePlay (Mega) » ; lp-commandlets, table des cartes, avec une ligne LPImportLegacyStreetMap.
  • Texte (lp-city § 9) : « Ancienne carte Mega = UStreetMap UE4 cuit, non versionné (legacy −7, ue4 = 0, drapeaux 0x80000000), propriétés étiquetées. Lecture hors moteur : Tools\LireCarteUE4.py --totaux ; reprise : LPImportLegacyStreetMap (réflexion, -DryRun) ; chaîne : RepriseCarte.ps1 (Lire, Creer, Importer, Classic, ODbL). Maillage statique : -Flat (Londres 1,59 % ; défaut et -Unlit 58 %). Triangles classiques ≈ 3·Pb − 2·B (écart de 0 à −0,18 %) ; environ 20 o par triangle dans l'archive. Jamais d'asset de travail sous Content\ (cuisson cassée, MAPDL1-P1). Les données (sans lat/lon ni identifiants OSM) se livrent en GeoJSON en plan local (SPEC-07). »

P2

R6. Exécutants haiku et chemins sous Git Bash

  • Faits :
    • EXEC-1 s'est arrêté sur un code 64 : le chemin du script, qui contient une espace, n'était pas entre guillemets dans Git Bash (MAPDL1-AUTO-EXEC-1.md).
    • Avec un chemin absolu entre guillemets et des barres obliques, le lot 1 est passé (5 villes sur 5) sans aucune décision à prendre (AUTO-FIN § 2).
    • Snapshot.ps1 ne pose pas de code de sortie : il faut $global:LASTEXITCODE = 0 avant l'appel.
    • Un if à un seul élément devient un scalaire : il faut @(if …) (JOURNAL-BROUILLON, 14:15).
  • Règles :
    • une brève pour haiku donne chaque commande en entier, avec un chemin absolu entre guillemets et des / ;
    • elle ne laisse aucun choix ;
    • elle donne le code attendu et l'arrêt sur tout écart.
  • Où : sk-windows-shell ; agent lp-builder ; sk-orchestrate (fiche pour un modèle réduit).
  • Texte (sk-windows-shell) : « Git Bash et chemin avec espace : pwsh -NoProfile -File "D:/Game/LifePlay-master 5.8/Tools/X.ps1" (guillemets, /). Sans guillemets : code 64. Tools\Snapshot.ps1 ne pose pas de code : $global:LASTEXITCODE = 0 avant l'appel. PowerShell : un if qui rend un seul élément est un scalaire ; écrire @(if …). »

R7. Dépassement du budget de tours (S7 : 62 pour 40)

  • Fait : lp-impl (sonnet) a utilisé 62 tours pour 40 (MAPDL1-S7-IMPL.md). Causes déclarées :

    • débogage de commandes inline ;
    • l'unité de Height ;
    • des essais ajoutés hors de la fiche (un vrai passage d'ODbL en plus du -ABlanc demandé).

    La fiche couvrait 3 outils liés physiquement, l'écriture en place et 3 villes d'essai, au niveau N3 avec 40 tours.

  • Règles :

    • une fiche qui touche 3 outils avec des essais mesurés reçoit 60 tours ;
    • les commandes répétées passent par un script ponctuel Saved\<lot>\ dès le 2e essai, pas en inline ;
    • aucun essai hors de la fiche sans le noter comme écart avant de le lancer.
  • Où : sk-orchestrate (barème du budget) ; agent lp-impl ; sk-protocol § 8.

  • Texte (lp-impl) : « Une commande longue ou répétée (pwsh inline, chemins avec \) passe par un script ponctuel Saved\<lot>\ dès le 2e essai. Un essai que la fiche ne demande pas ne se lance pas ; on le propose dans le compte rendu. »

  • Texte (sk-orchestrate) : « Budget : 3 fichiers ou plus, plus des essais mesurés = 60 tours (N3), pas 40. »

R8. Mise en page Slate : contrôle obligatoire hors de la zone qui défile ; habillage des chemins

  • Faits :
    • Dans COM31, la case d'accord était dans la même SScrollBox (plafonnée par SBox::MaxDesiredHeight) que la licence dépliée : elle passait sous le cadre (cas B2, TESTS-02 § E).
    • AutoWrapText ne coupe qu'entre deux mots : un chemin sans espace dépasse (B8).
    • Correctifs W1 :
      • la case et les messages sortent de la zone qui défile ;
      • .WrappingPolicy(ETextWrappingPolicy::AllowPerCharacterWrapping) (STextBlock.h:121, TextLayout.h:72) ;
      • la hauteur de la zone suit le viewport (UWidgetLayoutLibrary::GetViewportScale).
  • Règles :
    • les contrôles obligatoires (case d'accord, boutons) et les messages ne vont jamais dans une zone qui défile ;
    • tout texte qui peut contenir un chemin ou une URL reçoit AllowPerCharacterWrapping ;
    • une fenêtre se vérifie en 1280×720.
  • Où : agent lp-impl (rubrique Slate et UMG) ; lp-ue-compat (API Slate 5.8).
  • Texte : « Slate : les contrôles obligatoires et les messages hors de la SScrollBox (plafonnée par SBox::MaxDesiredHeight, qui peut suivre le viewport : MaxDesiredHeight_Lambda + UWidgetLayoutLibrary::GetViewportScale). Chemin ou URL : .WrappingPolicy(ETextWrappingPolicy::AllowPerCharacterWrapping), car AutoWrapText ne coupe qu'entre deux mots. Vérifier en 1280×720. Source : MAPDL1, essai COM31 (B2, B8). »

R9. Fichier partiel vide après un échec réseau

  • Fait : CreateFileWriter(…, FILEWRITE_Append) crée le fichier, et son dossier, avant le premier octet. L'échec voulu de B5 (DNS) a laissé Saved\Downloads\lpm_city_manila\…zip.part de 0 octet dans un dossier visible (B9). Correctif W2 :
    • le .part est écrit à côté du zip ;
    • à l'échec et à l'annulation, un .part vide est déplacé dans _rejet\ (SetAsideEmptyPart), sans aucun Delete.
  • Règle : un téléchargement qui échoue sans recevoir d'octet ne laisse ni fichier ni dossier visible. On le range (déplacement), on ne le supprime pas.
  • Où : agent lp-impl ; lp-ue-compat (HTTP).
  • Texte : « HTTP en flux (SetResponseBodyReceiveStream) : le .part existe dès l'ouverture. À l'échec ou à l'annulation, s'il fait 0 octet, le déplacer dans _rejet\ ; pas de sous-dossier par téléchargement. Source : MAPDL1 W2. »

R10. Le cahier d'essai se calcule comme le code

  • Fait : le cahier attendait « Download (21 MB) » pour 22 075 120 octets. Le jeu affiche 22, car il arrondit au-dessus (LPCityMapsSubsystem.cpp:734). C'est le cahier qui avait tort (TESTS-02 A1).
  • Règle : une valeur attendue se calcule par la formule du code, qu'on cite, et non de tête.
  • Où : lp-doc (gabarit FIT) ; agent lp-writer.
  • Texte : « Valeur attendue d'un affichage : la calculer par la formule du code, avec fichier:ligne (arrondi, unités). Exemple : 22 075 120 o → « 22 MB » (Mo arrondi au-dessus). »

P3

R11. Crochet ecriture-gardien et agents de lecture

  • Fait observé dans MAPDL1 : une commande Bash de lp-validator (E3 bis) a été refusée par le crochet, à cause d'un accent grave dans le texte. C'était un faux positif, sans effet ; l'agent l'a relancée sans ce caractère (MAPDL1-E3B-VAL.md, compte rendu).
  • Non observé dans MAPDL1 : le blocage des agents de collecte que cite Big Boss. Big Boss le complète avec ses propres preuves.
  • Règle : pour un agent sans Edit, pas d'accent grave ni de > dans les commandes du shell. Les recherches passent par Grep ou Read.
  • Où : sk-protocol § 7 (agents sans Edit) ; hooks\cas-v2.jsonl (cas d'essai).
  • Texte : « Agent sans Edit : aucune commande shell avec accent grave, > ni ->, même dans du texte cité ; le crochet ecriture-gardien les refuse (faux positif, MAPDL1-E3B). Reformuler, ou passer par Grep et Read. »

R12. Outils liés physiquement : écriture en place

  • Fait : IndexCartes, LireCarteUE4, RepriseCarte et RecetteCarte sont des liens physiques entre le jeu et l'addon. Ils ont été écrits par [IO.File]::WriteAllBytes, qui tronque le même fichier. Les MD5 sont identiques des deux côtés et fsutil montre 2 liens (S6-1-IMPL, S7-IMPL). La mémoire du projet le disait déjà ; les fiches l'ont rappelé à chaque fois.
  • Règle : la règle est déjà en mémoire ; il faut l'écrire dans le skill.
  • Où : lp-paths (Outils du jeu) ; agents lp-impl et lp-writer.
  • Texte : « Beaucoup de fichiers de Tools\ sont liés physiquement à l'addon : Edit et Write rompent le lien. Vérifier par fsutil hardlink list ; écrire en place par [IO.File]::WriteAllBytes(<Tools>, [IO.File]::ReadAllBytes(<brouillon>)) ; relire les 2 liens et les 2 MD5. »

R13. EtatDir.ps1 ne connaît pas un nouveau lot

  • Fait : Build.ps1 a écrit ses résumés dans etat\MAPDL1-E2B\, etat\MAPDL1-E2T\ et etat\MAPDL1-COM31\, à la racine d'etat\. Ils ont été déplacés à la clôture (MAPDL1-BILAN § 6).
  • Règle : à l'ouverture d'un lot, on ajoute sa règle à EtatDir.ps1, ou on passe -EtatDir à chaque Build.ps1 et à chaque RunCommandlet.ps1.
  • Où : lp-lot (Avant toute modification) ; agent lp-builder (passer -EtatDir si la fiche le donne).
  • Texte : « Nouveau lot : règle dans Tools\EtatDir.ps1, ou -EtatDir <etat>\<projet>\<lot> sur chaque Build.ps1 / RunCommandlet.ps1. Sinon, les résumés vont à la racine d'etat\ (MAPDL1). »

R14. Avertissement préexistant à séparer d'un effet nouveau

  • Fait : Accessed None … property GI in /Game/UI/CityMenu.CityMenu_C apparaît 5 fois dans l'essai COM31. Il figure déjà dans les 6 derniers journaux de COM30, sans E1 (TESTS-02 § E).
  • Règle : avant d'attribuer un avertissement à un lot, on le compte dans les journaux de la build précédente.
  • Où : lp-validate § 3 ; agent lp-validator.
  • Texte : « Avertissement en jeu : le compter dans les journaux de la build d'avant (Saved\Logs\*.log) avant de l'attribuer au lot. Exemple : CityMenu GI (Accessed None), préexistant à MAPDL1. »

Fichiers

  • A Docs/Migration/etat/REL/MAPDL1/MAPDL1-REX-2026-10-22.md
  • Aucun skill ni agent n'est modifié.