LifePlay-Revival/Docs/Migration/etat/ETAT2/ETAT2-T1-CART.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

453 lines
45 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.

# ETAT2-T1-CART — cartographie du petit lot ETAT2 (scripts, gabarits, etat/ 5.8, sources de mods)
Fiche ETAT2-T1 — Niveau N3 — Modèle prévu lp-cart | utilisé Opus 5.5 (`claude-opus-5-5`, identifiant donné par l'environnement de l'agent) — Agent lp-cart — Skills lp-paths, lp-commandlets, lp-build (non chargé : cité par la fiche, non présent dans le contexte), sk-protocol (+ ue-cpp-build chargé, non utilisé)
Date : 2026-10-09, relevés entre 14:45 et 15:05. Lecture seule partout sauf ce fichier. Aucun lancement de commandlet ni de compilation, aucune commande git d'écriture, aucun commit.
Preuve : « établi » = commande rejouable ou `fichier:ligne` ; « estimé » = déduit (raisonnement donné) ; « incertain » = à trancher (essai nommé).
Abréviations : `R5` = `D:\Game\LifePlay-master 5.5\Docs\Migration\etat` ; `R8` = `D:\Game\LifePlay-master 5.8\Docs\Migration\etat` ; `A55` = checkout addon `D:\Game\LifePlay-Sandbox` ; `A58` = worktree addon `D:\Game\LifePlay-Sandbox-5.8`.
## 0. Environnement (établi)
| Élément | Valeur | Commande |
|---|---|---|
| Jeu 5.5 | branche `main`, HEAD `1825884`, arbre propre | `git -C "D:\Game\LifePlay-master 5.5" status --porcelain` → vide |
| Jeu 5.8 | **clone séparé** (pas un worktree : `git rev-parse --git-common-dir` = `.git` dans les deux), branche `ue5.8`, HEAD `fc63060`, `main` ancêtre de `ue5.8` (9 commits d'avance, 0 de retard) | `git merge-base --is-ancestor main ue5.8` ; `git log --oneline main..ue5.8 \| wc -l` = 9 |
| Jeu 5.8 : session concurrente | **active** : 8 fichiers modifiés non commités (`.gitignore`, docs 29, Journal, Registre, `LifePlay.uproject`, 3 fichiers `Source/LifePlayEditorTools`) ; lot `STM` (doc 29 l. 186, projet ST) ; CHG-260 écrit mais non commité (`Journal_Modifications.md:1134`) ; derniers écrits : `R8\STM_Build_20261009-144519.txt` (14:48), `Saved\Logs\portage\STM_EditorHeadless_20261009-145312.log` (14:56) | `git -C "…5.8" diff --stat` ; `ls -lt` |
| Addon actif pour les skills | `A55`, branche `lot/DC3-atelier`, HEAD `6295829` ; les jonctions `.claude\skills` des **deux** copies du jeu pointent vers `A55\Tools\claude\skills` | `pwsh … (Get-Item '…\.claude\skills').Target` |
| Addon 5.8 | `A58`, branche `ue5.8`, HEAD `ce2e269` ; `lot/DC3-atelier` et `ue5.8` ont divergé (aucune n'est ancêtre de l'autre) | `git merge-base --is-ancestor` (deux sens, sans sortie) |
| Skills de `A58` | **non chargés** (aucune jonction) et en retard : `lp-paths` sans la section « Sources binaires des mods » (`A55 lp-paths:48-54`), `lp-validate` sans `:75-78`, `lp-build` d'U3 | `diff -r A55\Tools\claude\skills A58\Tools\claude\skills` |
| Journal des CHG | tenu sur `ue5.8` seulement (CHG-252 à 260) ; `main` s'arrête à CHG-251 | `grep CHG-258` Journal 5.8 l. 1136 |
| PowerShell | 7.6.6 | `pwsh -NoProfile -Command $PSVersionTable.PSVersion` |
## 1. Inventaire chiffré
### 1.1 Points d'appel sous `etat` dans les scripts (établi)
Commande : `grep -n -i "etat" Tools/*.ps1` dans chaque copie, puis lecture intégrale des 5 scripts concernés ; `grep -rn -i -w etat Tools` (sous-dossiers) : aucun autre script. Scripts du jeu : 24 fichiers (5.5) et 26 (5.8) sous `Tools` (`find Tools -type f \( -name '*.ps1' -o -name '*.py' -o -name '*.bat' -o -name '*.cmd' \) | wc -l`).
**Copie 5.5 (`main`)**
| Script:ligne | Opération | Chemin construit | Paramètres existants |
|---|---|---|---|
| `RunCommandlet.ps1:8` | aide | `Docs\Migration\etat\<Lot>_<Commandlet>_<horodatage>.txt` | — |
| `RunCommandlet.ps1:28` (+ `:29` `New-Item`, `:59` `Set-Content`) | **écriture racine** | `<ProjectRoot>\Docs\Migration\etat\<Lot>_<Commandlet>_<yyyyMMdd-HHmmss>.txt` | `-Lot` (obligatoire), `-Commandlet`, `-Args`, `-ProjectRoot`, `-Engine` (défaut `UE_5.5` en dur, `:20`) |
| `ReimportCorrectif.ps1:13` | aide | `Docs/Migration/etat/<Id>_*` | — |
| `ReimportCorrectif.ps1:34` | dossier `$etat` = **racine** | `<ProjectRoot>\Docs\Migration\etat` | `-Id`, `-ProjectRoot` (`:30`, dernier paramètre) |
| `ReimportCorrectif.ps1:44, 60, 69, 84, 87` | 5 appels `RunCommandlet.ps1 -Lot $Id` → écritures racine indirectes | `<Id>_<Commandlet>_<stamp>.txt` | — |
| `ReimportCorrectif.ps1:48` | écriture | `$etat\<Id>_dump_<avant\|apres>_<bp>_<fn>.txt` | `-Graphs` |
| `ReimportCorrectif.ps1:50` | **`Remove-Item` par motif** | `$etat\<Id>_LPDumpFunction_*.txt` | — |
| `ReimportCorrectif.ps1:62` | écriture | `$etat\<Id>_dryrun.txt` | — |
| `ReimportCorrectif.ps1:64` | **`Remove-Item` par motif** | `$etat\<Id>_<Commandlet>_*.txt` | `-Commandlet` |
| `ReimportCorrectif.ps1:70` | écriture | `$etat\<Id>_application.txt` | — |
| `ReimportCorrectif.ps1:71` | **`Remove-Item` par motif** | `$etat\<Id>_<Commandlet>_*.txt` | — |
| `ReimportCorrectif.ps1:77-78` | lecture | `$etat\<Id>_dump_avant\|apres_<bp>_<fn>.txt` | — |
| `ReimportCorrectif.ps1:80` | écriture | `$etat\<Id>_diff_<bp>_<fn>.txt` | — |
| `CheckIntegrity.ps1:25` (lu `:78-79` par `-Ref427`, écrit `:49-50` par `-InitRef427`) | lecture (écriture unique en L0) | `<ProjectRoot>\Docs\Migration\etat\L0_ref427.csv` (**resté à la racine**, décision ETAT-T2) | `-Ref427`, `-InitRef427` |
| `AssetHeaders.ps1:13` | exemple d'aide seulement | `-Csv Docs\Migration\etat\headers_BPs.csv` | `-Csv` |
**Copie 5.8 (`ue5.8`)**
| Script:ligne | Opération | Chemin construit | Paramètres existants |
|---|---|---|---|
| `RunCommandlet.ps1:8` | aide | idem 5.5 | — |
| `RunCommandlet.ps1:36` (+ `:37`, `:67`) | **écriture racine** | idem 5.5 | `-Lot`, `-Commandlet`, `-Args`, `-ProjectRoot`, `-Engine` (défaut vide → `Tools\Engine.ps1`, `:29-30`) |
| `Build.ps1:7` | aide | `Docs\Migration\etat\<Lot>_Build_<horodatage>.txt` | — |
| `Build.ps1:52` | **écriture racine** (mode `-FromLog`) | `<ProjectRoot>\Docs\Migration\etat\<Lot>_BuildLog_<stamp>.txt` | `-Lot` (obligatoire), `-FromLog` |
| `Build.ps1:61` (+ `:71` `New-Item`, `:127` `Set-Content`) | **écriture racine** | `<ProjectRoot>\Docs\Migration\etat\<Lot>_Build_<stamp>.txt` | `-Lot`, `-Target`, `-Config`, `-Platform`, `-ExtraArgs`, `-ProjectRoot`, `-Engine` (dernier, `:40`) |
| `ReimportCorrectif.ps1:13, 35, 45/61/70/85/88, 49, 51, 63, 65, 71, 72, 78-79, 81` | identique à 5.5 décalé de +1 ligne (seul l'en-tête diffère : `:15`, exemple `:18-20`) | idem | idem (`-ProjectRoot` `:31`, dernier) |
| `CheckIntegrity.ps1:28` | **ne lit plus `etat`** : référence `$BackupRoot\ref_modules_<version>.csv` ; `-Ref427`/`-InitRef427` retirés en U2 | — | `-InitRef` |
| `AssetHeaders.ps1:13` | exemple d'aide | idem 5.5 | `-Csv` |
| `Engine.ps1` | aucune référence à `etat` ; se présente comme « point unique du moteur … et des dossiers de sortie » (`:3`) | — | — |
**Appelants externes** : `AnimPipeline.ps1` de l'addon appelle le `RunCommandlet.ps1` du jeu avec `-Lot AP7` en dur (`A58\Tools\anim\AnimPipeline.ps1:120,123` ; `A55\…:118,121`) → avec la convention proposée, ses résumés iraient dans `etat\anim\AP7\` (cohérent). Aucun script de l'addon n'écrit sous `etat` (`grep -rn -i etat` : seulement `etat.json` d'`AnimPipeline`, sans rapport).
**Corrections à la proposition ETAT-T1 § 4** (établi) : (1) `CheckIntegrity.ps1` 5.8 ne lit pas `L0_ref427.csv` (voir ci-dessus) : seule la copie 5.5 en dépend ; (2) `modele-sequencage.md:123` (mémoire) dit déjà `etat/<projet>/<P#>/` : rien à changer ; (3) le nettoyage par motif de `ReimportCorrectif.ps1` ne supprime que les résumés `LPDumpFunction` et ceux de la commandlet du correctif, pas ceux de `LPCheckMeshAssignment` ni `CompileAllBlueprints` (`:84`, `:87` sans `Remove-Item` derrière).
**Constat de risque inter-copies** (établi, `Build.ps1:55`) : `Get-Process -Name 'UnrealEditor', 'UnrealEditor-Cmd'` sans filtre de chemin : un commandlet lancé dans la copie 5.5 fait sortir en code 3 un `Build.ps1` lancé au même moment dans la copie 5.8 (et inversement pour un éditeur). Conséquence pour le plan : pas d'essai réel de commandlet en 5.5 pendant la session STM.
### 1.2 Gabarits `etat` des skills (établi)
Commande : `grep -rn -E "etat[\\/]" <addon>\Tools\claude\skills` → `A55` : 26 lignes dans 9 fichiers ; `A58` : 23 lignes dans 9 fichiers (`grep -rn … | wc -l`, `grep -rl … | wc -l`). Skills utilisateur `%USERPROFILE%\.claude\skills` : 0 fichier. Mémoire : 1 gabarit racine (`lifeplay-build-pitfalls.md:15`).
Lignes qui annoncent encore la **racine** (à changer) dans `A55` : `lp-build:33`, `lp-build:118-119`, `lp-commandlets:22`, `lp-lot:50-51`, `lp-paths:32`, `lp-validate:50` (6 passages). Lignes figées sur le projet `U58` alors que les projets ST (doc 29 l. 62) et OB (doc 30 l. 42) arrivent : `lp-build:115`, `lp-validate:14`, `lp-validate:83` (3). Section à compléter par le script de (d) : `lp-paths:49-51`. Déjà conformes : `lp-doc/gabarits.md:3,5`, `lp-doc:39`, `lp-env:8`, `lp-lot:3,48-49`, `lp-paths:33,52-53`, `lp-ue-compat:15-16`, `lp-validate:23,62,71`. Dans `A58` les mêmes passages sont aux lignes `lp-build:32,110,113`, `lp-validate:79` (texte plus ancien).
Docs NN (gabarits, pas l'historique) : `03_Plan_Migration_Tests.md:107` (5.5) / `:109` (5.8) `Docs/Migration/etat/<lot>_run_<date>.log` ; `09_Commandes_Utiles.md:60` / `:61` `-CSV=Docs/Migration/etat/streetmap.csv` (commande `grep -rn -E "etat[\\/]+(<|\$|\{)[A-Za-z]" Docs --exclude-dir=etat`, plus `grep -n etat 09_*`).
### 1.3 `etat/` des deux copies (établi)
| Mesure | R5 | R8 | Commande |
|---|---|---|---|
| Fichiers à la racine | **5** (`ETAT-INVENTAIRE-PROPOSITION.md`, `ETAT-T2-REORG.md`, `INVENTAIRE.md`, `L0_ref427.csv`, `MAPPING.csv`) | **333** (316 `.txt`, 16 `.csv`, 1 `.md`) | `find . -maxdepth 1 -type f \| wc -l` ; recompte `Get-ChildItem -File` = 333 |
| Fichiers au total | 616 | **472** | `find . -type f \| wc -l` ; recompte PowerShell 472 |
| Fichiers en sous-dossiers | 611 | 139 (sandbox 70, VQ 12, U58 12 = UA 8 + U0 4, PUB2 11, L4-CX-B02_essai1_rejete 10, PROP 9, SK 6, commit_plan 5, PUB1 4) | `for d in */; do find "$d" -type f \| wc -l; done` |
R5 n'a reçu **aucun** nouveau fichier à la racine depuis ETAT-T2 (les scripts 5.5 n'ont pas servi). R8 est passé de 316 (ETAT-T1) à 333 fichiers à la racine (+17 : U7, U7-VAL, U7b, STM).
Classement de la racine R8 (commande de classement d'ETAT-T1 étendue aux préfixes `U<n>[b][-X]`, `UA`, `STM`) : `AP2=2 AP3=5 AP4=7 AP5=18 AP6=5 AP7=51 COMMIT-CART=1 DC2=4 DC3=1 DOC-MOD=4 L0=8 L1=2 L2=1 L4-CX-B01=7 L4-CX-B02b=10 L4-CX-B03=5 L4-CX-B04=10 L4-CX-B07=12 L4-CX-B08=4 L5-diag=21 L6e=2 L6e-CX-B09=11 L6e-CX-B09b=3 L6e-CX-B09c=1 L6f=13 L7a=8 L7b=6 L7d=9 L7h=8 L7i=19 L7j=4 L7l=2 PairCol=10 PawnDyn=4 PawnGlobal=3 STM=2 STUDIO-EST=6 U2=1 U3=2 U3-T2=1 U3-VAL=2 U4=2 U4-T7=1 U5=13 U7=10 U7-VAL=4 U7b=8` (somme 333).
Confrontation à `R5\MAPPING.csv` et MD5 (script dans le dossier temporaire de session : pour chaque fichier R8, recherche de `ancien_chemin_relatif`, puis `md5sum` R8 contre `R5\<nouveau_chemin_relatif>`) :
| Groupe R8 | Fichiers | État |
|---|---|---|
| Racine présente dans `MAPPING.csv` | **283** | 283 MD5 identiques à R5 (0 différent) |
| `L0_ref427.csv` (racine) | 1 | identique à `R5\L0_ref427.csv` |
| Racine propre à R8 (hors `MAPPING.csv`, absente de R5 par nom : `find R5 -name`) | **49** | AP7 3, U2 1, U3 5 (U3 2 + U3-T2 1 + U3-VAL 2), U4 3 (U4 2 + U4-T7 1), U5 13, U7 14 (U7 10 + U7-VAL 4), U7b 8, STM 2 |
| Sous-dossiers | 139 | **139/139 MD5 identiques** à leurs homologues R5 (PUB1/PUB2/commit_plan → `publication\…`, essai 1 → `portage55\L4-CX-B02\essai1_rejete\`, autres même chemin) |
Contrôles : 283 + 1 + 49 = 333 ; 333 + 139 = 472. Couverture : 313 des 317 lignes de `MAPPING.csv` ont une source dans R8 ; les 4 absentes sont `AP7_LPAnimEval_20261008-175103.txt`, `…-181017.txt`, `U1_LPAuditBlueprintCalls_20261008-145127.txt`, `…-145335.txt` (fichiers propres à R5, déjà notés en ETAT-T1). Recompte PowerShell des 49 : `U*`/`STM` 46 + AP7 du 08/10 ≥ 18:47 3.
Citations des 49 fichiers propres à R8 : **60 occurrences, 34 noms distincts, dans 21 fiches de `R5\U58\`** (U2-T4-BUILD, U2-VAL, U3-T2-BUILD, U3-T3-TEST, U3-T3b-TEST, U3-VAL, U4-T4-BUILD, U4-T6-VAL, U4-VAL, U5-T1-CART, U5-T2-AVANT, U5-T3-RESAVE, U5-VAL, U7-T8-BUILD, U7-T8b-BUILD, U7-T10-BUILD, U7-T13-BUILD, U7-T14-BUILD, U7-VAL, U7b-T5-IMPL, U7b-T6-VAL), surtout sous la forme `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\<fichier>` (36) ; 0 citation dans les Docs NN des deux copies (`grep -rnoFf uniq49.txt Docs --exclude-dir=etat`). Commande : `grep -rhoFf uniq49.txt R5/U58 | wc -l` (60) et `| sort -u | wc -l` (34).
### 1.4 Sources de mods hors git (établi)
| Mesure | `A55` | `A58` | Commande |
|---|---|---|---|
| Règle git | `.gitignore:38` `/ModSources/*/Content/` | idem `:38` | `grep -n ModSources .gitignore` |
| `ModSources/<id>/Content` | freeanims 20, quaternius 84, pocolov 70 = **174 fichiers, 88 888 626 octets** | identique | `find <id>/Content -type f` ; `Get-ChildItem … Measure-Object Length -Sum` |
| Comparaison chemin + MD5 | — | **174/174 identiques** (copie U7-T15 faite) | `md5sum` des deux arbres, `diff -q` |
| Fichiers suivis par git sous `ModSources` | 25 / 89 / 15 | 25 / 89 / 15 | `git ls-files ModSources` |
| Résidus de cuisson `ModSources/*/Saved` (ignorés par `.gitignore:6`) | 417 | 417 | `find ModSources -path '*/Saved/*' -type f \| wc -l` |
| Points de reparse sous `ModSources` | 0 | 0 | `Get-ChildItem -Recurse -Attributes ReparsePoint` |
| Racine du jeu de l'atelier | `Config\LPSandbox.ini:46` `GameRoot=..\LifePlay-master 5.5` | `:46` `..\LifePlay-master 5.8` | `grep -n GameRoot` |
Mécanisme à respecter (établi, `A58\Tools\ModSource.ps1:25-45`) : `Mount-ModSource` **déplace** `ModSources\<id>` vers `<jeu>\Mods\<id>` pendant un travail (`BuildMod.ps1:239`, remis par `:305`) : un mod monté n'a plus de `ModSources\<id>\<id>.uplugin`. `Mods\` des deux jeux : vides (`ls`). Report ouvert : doc 21 (5.8) l. 217 et ERR-046 (Registre 5.8 l. 53, « Ouvert : transfert hors git à documenter / scripter »).
## 2. Convention proposée pour les scripts (une seule) et diffs (non appliqués)
### 2.1 Convention
Un fichier commun **`Tools\EtatDir.ps1`** (nouveau, texte identique sur `main` et `ue5.8`), dot-sourcé par les trois scripts, avec une fonction `Resolve-LPEtatDir <ProjectRoot> <Lot> [<EtatDir>] [-NoCreate]` :
1. `-EtatDir` non vide (paramètre ajouté aux trois scripts) : dossier imposé (absolu, ou relatif à `Docs\Migration\etat`).
2. Sinon : table versionnée lot → projet (première règle qui correspond, sensible à la casse) ; le groupe capturé donne le dossier du lot, rôle et tâche retirés (`U7-VAL` → `U58\U7`, `U3-T2` → `U58\U3`, `AP5-PD` → `anim\AP5`, `L6e-CX-B09b` → `portage55\L6e`, conforme au rangement d'ETAT-T2).
3. Lot hors table : `etat\<Lot>\` + avertissement (jamais la racine, jamais d'échec ; cohérent avec les dossiers à plat existants `SK\`, `PROP\`, `ETAT2\`). Variante à décider (D2).
4. Garde : lot limité à `[A-Za-z0-9._-]` (pas de `..\`, pas de caractère générique) ; refus si le dossier résolu contient `* ? [ ]` → les `Remove-Item` par motif ne peuvent pas être élargis par le nom de dossier.
5. Chaque copie écrit dans **son** `etat` (`$ProjectRoot` inchangé) : la 5.8 dans `R8\<projet>\<lot>\`, la 5.5 dans `R5\<projet>\<lot>\`.
La table est dans le script (et non dans `etat\`, ignoré par git, donc absent d'un nouveau clone).
### 2.2 Texte proposé de `Tools\EtatDir.ps1` (ASCII, comme les scripts existants)
```powershell
<#
.SYNOPSIS
Dossier des preuves d'un lot : Docs\Migration\etat\<projet>\<lot>\ (lot ETAT2). A dot-sourcer, pas a lancer.
.DESCRIPTION
Usage : . "$PSScriptRoot\EtatDir.ps1" ; $dir = Resolve-LPEtatDir $ProjectRoot $Lot $EtatDir
-EtatDir non vide : dossier impose (absolu, ou relatif a Docs\Migration\etat).
Sinon : premiere regle de $LPEtatRules qui correspond au lot (casse comprise) ; groupe 1 = dossier du lot.
Lot hors table : Docs\Migration\etat\<Lot>\ avec un avertissement (jamais la racine de etat\).
Cree le dossier s'il manque, sauf -NoCreate. Index des projets : Docs\Migration\etat\INVENTAIRE.md (hors git).
#>
# Ordre significatif : STUDIO-EST avant ST* ; PROP, SK et ETAT* sont des dossiers a plat.
$LPEtatRules = @(
@{ Re = '^(STUDIO-EST|PawnGlobal|PawnDyn)(?:-|$)'; Proj = 'post-v1' }
@{ Re = '^(U\d+[a-z]?|UA)(?:-|$)'; Proj = 'U58' }
@{ Re = '^(AP\d+)(?:-|$)'; Proj = 'anim' }
@{ Re = '^(L4-CX-B\d+[a-z]?|L5-diag|L\d+[a-z]?)(?:-|$)'; Proj = 'portage55' }
@{ Re = '^(S\d+|SB\d+|DC\d+|PairCol|DOC-MOD)(?:-|$)'; Proj = 'sandbox' }
@{ Re = '^(VQ\d+)(?:-|$)'; Proj = 'VQ' }
@{ Re = '^(PUB\d+)(?:-|$)'; Proj = 'publication' }
@{ Re = '^(ST[A-Z]?\d*[a-z]?)(?:-|$)'; Proj = 'ST' }
@{ Re = '^(OB[A-Z]?\d*[a-z]?)(?:-|$)'; Proj = 'OB' }
@{ Re = '^(PROP|SK|ETAT\d*)(?:-|$)'; Proj = '' }
)
function Resolve-LPEtatDir([string]$ProjectRoot, [string]$Lot, [string]$EtatDir = '', [switch]$NoCreate) {
if ($Lot -cnotmatch '^[A-Za-z0-9][A-Za-z0-9._-]*$') { throw "EtatDir.ps1 : lot '$Lot' invalide (lettres, chiffres, . _ - seulement)" }
$base = Join-Path $ProjectRoot 'Docs\Migration\etat'
if ($EtatDir) {
$dir = if ([IO.Path]::IsPathRooted($EtatDir)) { $EtatDir } else { Join-Path $base $EtatDir }
} else {
$dir = $null
foreach ($r in $LPEtatRules) {
if ($Lot -cmatch $r.Re) {
$dir = if ($r.Proj) { Join-Path $base (Join-Path $r.Proj $Matches[1]) } else { Join-Path $base $Matches[1] }
break
}
}
if (-not $dir) {
$dir = Join-Path $base $Lot
Write-Warning "EtatDir.ps1 : lot '$Lot' hors table, preuves dans $dir (ajouter une regle a Tools\EtatDir.ps1)"
}
}
if ($dir -match '[\*\?\[\]]') { throw "EtatDir.ps1 : caractere generique dans $dir" }
if (-not $NoCreate) { New-Item -ItemType Directory -Force $dir | Out-Null }
$dir
}
```
Table d'essai attendue (VAL, avec `-NoCreate`, aucun effet disque) : `U7-VAL`→`U58\U7` ; `U3-T2`→`U58\U3` ; `U7b`→`U58\U7b` ; `UA`→`U58\UA` ; `AP5-PD`→`anim\AP5` ; `AP7`→`anim\AP7` ; `L4-CX-B02`→`portage55\L4-CX-B02` ; `L6e-CX-B09b`→`portage55\L6e` ; `L5-diag`→`portage55\L5-diag` ; `L0`→`portage55\L0` ; `S2-T2`→`sandbox\S2` ; `DOC-MOD`→`sandbox\DOC-MOD` ; `STUDIO-EST`→`post-v1\STUDIO-EST` ; `STM`→`ST\STM` ; `STA-T1`→`ST\STA` ; `OBA-T1`→`OB\OBA` ; `SK-T1`→`SK` ; `ETAT2`→`ETAT2` ; `PROP`→`PROP` ; `O2`→`O2` + avertissement ; `..\x` → erreur ; `-EtatDir ETAT2\essai` → `ETAT2\essai`. (Estimé : les expressions ont été vérifiées à la main sur ces cas, pas exécutées.)
### 2.3 Diffs proposés (non appliqués)
Choix de placement (estimé, pour qu'un `cherry-pick` du commit `main` sur `ue5.8` passe sans conflit par fusion à trois voies) : ne toucher que des lignes et voisinages identiques dans les deux branches. `RunCommandlet.ps1` : nouveau paramètre inséré **entre `$Args` et `$ProjectRoot`** (contexte identique dans les deux branches ; la fin du bloc `param` diffère : `$Engine` 5.5 `:20` contre 5.8 `:25`) et dot-source placé juste avant `$sum` (le voisinage de `$ErrorActionPreference` diffère, `Engine.ps1` en 5.8). Effet sur l'appel positionnel : tous les appelants connus passent des paramètres nommés (`ReimportCorrectif.ps1` ×5, `AnimPipeline.ps1`, exemples d'aide) — établi par les `grep` du § 1.1.
**`Tools/RunCommandlet.ps1`** (5.5 ; en 5.8, mêmes hunks aux lignes 8, 23-24, 36)
```diff
@@ -5,6 +5,7 @@
.DESCRIPTION
Journal complet : Saved\Logs\portage\<Lot>_<Commandlet>_<horodatage>.log
Resume (lignes Error/Warning dedoublonnees, lignes de la commandlet) :
- Docs\Migration\etat\<Lot>_<Commandlet>_<horodatage>.txt
+ Docs\Migration\etat\<projet>\<lot>\<Lot>_<Commandlet>_<horodatage>.txt (dossier deduit du lot par
+ Tools\EtatDir.ps1 ; -EtatDir l'impose)
Retourne le code de sortie de la commandlet.
@@ -17,5 +18,6 @@ param(
[Parameter(Mandatory)][string]$Commandlet,
[string]$Args = '',
+ [string]$EtatDir = '',
[string]$ProjectRoot = (Split-Path $PSScriptRoot -Parent),
@@ -27,3 +29,4 @@
$log = Join-Path $ProjectRoot "Saved\Logs\portage\$name.log"
-$sum = Join-Path $ProjectRoot "Docs\Migration\etat\$name.txt"
+. "$PSScriptRoot\EtatDir.ps1"
+$sum = Join-Path (Resolve-LPEtatDir $ProjectRoot $Lot $EtatDir) "$name.txt"
New-Item -ItemType Directory -Force (Split-Path $log -Parent), (Split-Path $sum -Parent) | Out-Null
```
(Le lot est validé avant le lancement de la commandlet : `Resolve-LPEtatDir` précède `Start-Process`.)
**`Tools/ReimportCorrectif.ps1`** (5.5 ; 5.8 = mêmes hunks, lignes +1 sauf `:13`)
```diff
@@ -13 +13,2 @@
- Les preuves vont dans Docs/Migration/etat/<Id>_*. Ne commite pas : la validation reste humaine
+ Les preuves vont dans Docs/Migration/etat/<projet>/<lot>/<Id>_* (Tools\EtatDir.ps1 ; -EtatDir l'impose).
+ Ne commite pas : la validation reste humaine
@@ -29,3 +30,4 @@ param(
[string]$DryRunArgs = '-DryRun',
- [string]$ProjectRoot = (Split-Path $PSScriptRoot -Parent)
+ [string]$ProjectRoot = (Split-Path $PSScriptRoot -Parent),
+ [string]$EtatDir = ''
)
@@ -34 +36,3 @@
-$etat = Join-Path $ProjectRoot 'Docs\Migration\etat'
+. "$PSScriptRoot\EtatDir.ps1"
+# Dossier du lot, transmis tel quel a RunCommandlet : resumes, preuves et nettoyages ci-dessous dans ce seul dossier
+$etat = Resolve-LPEtatDir $ProjectRoot $Id $EtatDir
@@ -44 @@
- & "$PSScriptRoot\RunCommandlet.ps1" -Lot $Id -Commandlet LPDumpFunction -Args "-BP=$bp -Fn=$fn -Pins" | Out-Null
+ & "$PSScriptRoot\RunCommandlet.ps1" -Lot $Id -Commandlet LPDumpFunction -Args "-BP=$bp -Fn=$fn -Pins" -EtatDir $etat | Out-Null
@@ -60 @@
-& "$PSScriptRoot\RunCommandlet.ps1" -Lot $Id -Commandlet $Commandlet -Args $DryRunArgs | Out-Null
+& "$PSScriptRoot\RunCommandlet.ps1" -Lot $Id -Commandlet $Commandlet -Args $DryRunArgs -EtatDir $etat | Out-Null
@@ -69 @@
-& "$PSScriptRoot\RunCommandlet.ps1" -Lot $Id -Commandlet $Commandlet -Args $ApplyArgs | Out-Null
+& "$PSScriptRoot\RunCommandlet.ps1" -Lot $Id -Commandlet $Commandlet -Args $ApplyArgs -EtatDir $etat | Out-Null
@@ -84 @@
-& "$PSScriptRoot\RunCommandlet.ps1" -Lot $Id -Commandlet LPCheckMeshAssignment | Out-Null
+& "$PSScriptRoot\RunCommandlet.ps1" -Lot $Id -Commandlet LPCheckMeshAssignment -EtatDir $etat | Out-Null
@@ -87 @@
-& "$PSScriptRoot\RunCommandlet.ps1" -Lot $Id -Commandlet CompileAllBlueprints | Out-Null
+& "$PSScriptRoot\RunCommandlet.ps1" -Lot $Id -Commandlet CompileAllBlueprints -EtatDir $etat | Out-Null
```
Les trois `Remove-Item` (`:50`, `:64`, `:71`) **ne changent pas de texte**. Portée avant : `etat\<Id>_<Cmd>_*.txt` à la racine (où s'accumulaient tous les lots) ; après : le même motif dans le seul dossier `etat\<projet>\<lot>\` où `RunCommandlet` vient d'écrire (même `$etat`, transmis par `-EtatDir`) ; non récursif ; le préfixe `${Id}_` reste. Portée strictement plus étroite, pas élargie. Les anciens résumés restés à la racine (lots déjà faits) ne sont plus atteignables par ces motifs. Remarque (hors ETAT2) : ces suppressions contredisent `lp-commandlets:22` (« Ne jamais supprimer ») et la règle « rm KO » de la mémoire : décision D5.
**`Tools/Build.ps1`** (5.8 seulement ; absent de `main` : `ls Tools`)
```diff
@@ -6,2 +6,3 @@
Journal complet : Saved\Logs\portage\<Lot>_Build_<horodatage>.log
- Resume : Docs\Migration\etat\<Lot>_Build_<horodatage>.txt
+ Resume : Docs\Migration\etat\<projet>\<lot>\<Lot>_Build_<horodatage>.txt (dossier deduit du lot par
+ Tools\EtatDir.ps1 ; -EtatDir l'impose)
@@ -39,3 +40,4 @@ param(
[string]$ProjectRoot = (Split-Path $PSScriptRoot -Parent),
- [string]$Engine = ''
+ [string]$Engine = '',
+ [string]$EtatDir = ''
)
@@ -47,2 +49,4 @@
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
+. "$PSScriptRoot\EtatDir.ps1"
+$etatDir = Resolve-LPEtatDir $ProjectRoot $Lot $EtatDir -NoCreate # lot valide avant toute compilation
$argLine = ...
@@ -52 @@
- $sum = Join-Path $ProjectRoot "Docs\Migration\etat\${Lot}_BuildLog_$stamp.txt"
+ $sum = Join-Path $etatDir "${Lot}_BuildLog_$stamp.txt"
@@ -61 @@
- $sum = Join-Path $ProjectRoot "Docs\Migration\etat\${Lot}_Build_$stamp.txt"
+ $sum = Join-Path $etatDir "${Lot}_Build_$stamp.txt"
```
(`:71` `New-Item -ItemType Directory -Force (Split-Path $sum -Parent)` existe déjà et crée le dossier après le contrôle de l'éditeur : une sortie en code 3 ne crée rien.)
**`Tools/AssetHeaders.ps1:13`** (deux copies, cosmétique) : `-Csv Docs\Migration\etat\headers_BPs.csv` → `-Csv Docs\Migration\etat\<projet>\<lot>\headers_BPs.csv`.
**`Tools/CheckIntegrity.ps1`** : **aucun changement** (5.5 `:25` lit `etat\L0_ref427.csv`, resté à la racine ; 5.8 ne lit pas `etat`).
**Docs NN** (sur `ue5.8`, branche où vivent les docs à jour, étape DOC) : `03_Plan_Migration_Tests.md:109` → `Docs/Migration/etat/<projet>/<lot>/<lot>_run_<date>.log` ; `09_Commandes_Utiles.md:61` → `-CSV=Docs/Migration/etat/<projet>/<lot>/streetmap.csv`.
## 3. Gabarits des skills : texte proposé (addon `A55`, branche `lot/DC3-atelier`, actif par jonction)
| Fichier:ligne (A55) | Texte actuel (extrait) | Texte proposé |
|---|---|---|
| `lp-build/SKILL.md:33` | `` `<copie>\Docs\Migration\etat\<lot>_Build_<horodatage>.txt` `` | `` `<copie>\Docs\Migration\etat\<projet>\<lot>\<Lot>_Build_<horodatage>.txt` `` (dossier déduit du lot par `Tools\EtatDir.ps1`, `-EtatDir` pour l'imposer) |
| `lp-build/SKILL.md:115` | `` …\etat\U58\<lot>\<LOT>-Tn-BUILD.md `` | `` …\etat\<projet>\<lot>\<LOT>-Tn-BUILD.md `` (U58, ST, OB…) |
| `lp-build/SKILL.md:118-119` | « Résumés automatiques (`Build.ps1`, `RunCommandlet.ps1`) : restent dans `<copie>\Docs\Migration\etat\` ; la fiche cite leur chemin complet. » | « Résumés automatiques (`Build.ps1`, `RunCommandlet.ps1`, `ReimportCorrectif.ps1`) : `<copie>\Docs\Migration\etat\<projet>\<lot>\` de la copie qui les produit (table lot → projet de `Tools\EtatDir.ps1` ; lot hors table : `etat\<Lot>\` + avertissement) ; la fiche cite leur chemin complet. Résumés antérieurs à ETAT2 : `etat/MAPPING.csv` (5.5), `MAPPING-58.csv` (5.8). » |
| `lp-commandlets/SKILL.md:21-22` | « … résumé … : `Docs\Migration\etat\<Lot>_<Commandlet>_<horodatage>.txt`. Ne jamais supprimer. » | « … résumé … : `Docs\Migration\etat\<projet>\<lot>\<Lot>_<Commandlet>_<horodatage>.txt` (`Tools\EtatDir.ps1` ; `-EtatDir` impose un dossier). Ne jamais supprimer. » |
| `lp-lot/SKILL.md:50-51` | « Résumés automatiques de `Build.ps1` / `RunCommandlet.ps1` : `<copie>\Docs\Migration\etat\`, cités par leur chemin complet. » | « Résumés automatiques de `Build.ps1` / `RunCommandlet.ps1` : `<copie>\Docs\Migration\etat\<projet>\<lot>\` (dans la copie 5.8 : sa propre arborescence `etat`, mêmes noms de dossiers), cités par leur chemin complet. » |
| `lp-paths/SKILL.md:32` | `` `Docs\Migration\etat\` (résumés `.txt`) `` | `` `Docs\Migration\etat\<projet>\<lot>\` (résumés `.txt`, `Tools\EtatDir.ps1`) `` |
| `lp-paths/SKILL.md:49-51` | « … Avant `BuildMod`, le copier depuis `D:\Game\LifePlay-Sandbox\ModSources\<id>\Content` (copie, MD5 contrôlés ; U7-T15). État actuel : … » | « … Avant `BuildMod` : `.\Tools\SyncModSources.ps1 -Target <checkout>` (à blanc : liste NOUVEAU / IDENTIQUE / DIFFERENT / EN_TROP ; `-Apply` copie, MD5 relus ; ERR-046). État au 2026-10-09 : `A58` identique à `A55` (174 fichiers). » |
| `lp-validate/SKILL.md:14` | `` (`…\Docs\Migration\etat\U58\<lot>\`) `` | `` (`…\Docs\Migration\etat\<projet>\<lot>\`) `` |
| `lp-validate/SKILL.md:50` | `` `<copie>\Docs\Migration\etat\<lot>_LPTestStringCompat_<horodatage>.txt` `` | `` `<copie>\Docs\Migration\etat\<projet>\<lot>\<Lot>_LPTestStringCompat_<horodatage>.txt` `` |
| `lp-validate/SKILL.md:83` | `` …\etat\U58\<lot>\<LOT>-VAL.md `` | `` …\etat\<projet>\<lot>\<LOT>-VAL.md `` |
| `lp-paths/SKILL.md:43` (facultatif) | `` `Docs/Migration/etat/**/*.txt` `` | `` `Docs/Migration/etat/` (tout le dossier, `.gitignore:74` ; `:53` pour les `.txt`) `` |
Hors addon (orchestrateur) : mémoire `lifeplay-build-pitfalls.md:15` (`etat\<Lot>_<Commandlet>_<horodatage>.txt` → `etat\<projet>\<lot>\…`). Portage vers la branche `ue5.8` de l'addon (`A58`, non chargée) : décision D11.
## 4. Mapping proposé pour `R8` (copie 5.8)
Méthode : celle d'ETAT-T1/T2 (préfixe → projet/lot, `MAPPING.csv` réutilisé), plus un fichier `R8\MAPPING-58.csv` de mêmes colonnes (`ancien_chemin_relatif;nouveau_chemin_relatif;projet;lot;doc_NN;CHG`).
| Groupe | Fichiers | Cible dans R8 | Source du mapping |
|---|---|---|---|
| Racine identique à R5 | 283 | même `nouveau_chemin_relatif` que `MAPPING.csv` (portage55 165, anim 85, sandbox 19, post-v1 13, publication 1 `COMMIT-CART.md`, U58 0) | lignes de `MAPPING.csv` |
| Dossiers `PUB1`, `PUB2`, `commit_plan`, `L4-CX-B02_essai1_rejete` | 30 | `publication\PUB1|PUB2|commit_plan\`, `portage55\L4-CX-B02\essai1_rejete\` (déplacement de dossier, comme ETAT-T2) | lignes de `MAPPING.csv` |
| AP7 du 08/10 (18:47, 19:04, 19:23) | 3 | `anim\AP7\` | nouvelles lignes |
| U2 | 1 | `U58\U2\` | nouvelles |
| U3 (+ U3-T2, U3-VAL) | 5 | `U58\U3\` | nouvelles |
| U4 (+ U4-T7) | 3 | `U58\U4\` | nouvelles |
| U5 (dont `U5_streetmap_58.csv`, `U5_streetmap_apres.csv`) | 13 | `U58\U5\` | nouvelles |
| U7 (+ U7-VAL) | 14 | `U58\U7\` | nouvelles |
| U7b | 8 | `U58\U7b\` | nouvelles |
| **STM** (session en cours) | 2 au relevé, en croissance | **exclus** tant que STM est ouvert ; ensuite `ST\STM\` | nouvelles, après clôture |
| `L0_ref427.csv` | 1 | reste à la racine (aucun lecteur sur `ue5.8`) | décision D8 |
| Sous-dossiers en place (`sandbox` 70, `VQ` 12, `SK` 6, `PROP` 9, `U58\UA` 8, `U58\U0` 4) | 109 | inchangés | — |
Comptes : déplacements = 283 + 30 + 47 = **360** (+ STM ensuite) ; contrôle racine 283 + 47 + 2 (STM) + 1 (L0) = 333. Après : racine R8 = `L0_ref427.csv` + `MAPPING-58.csv` (+ STM tant qu'exclus) ; total 472 + 1. Projets après : portage55 175, anim 88 (85 + 3), sandbox 89, post-v1 13, publication 21, U58 56 (12 + 44), VQ 12, SK 6, PROP 9, + `ST\STM` (2+).
Exclusions : tout fichier `STM_*` et tout fichier de R8 plus récent que le début de la session STM (premier journal `STM_Build_20261009-144519`, 14:45:19) ; règle de contrôle avant déplacement : `find R8 -maxdepth 1 -newermt '2026-10-09 14:45'` doit ne lister que des `STM_*`.
Références cassées par ce déplacement : les 60 citations (34 noms, 21 fiches `R5\U58\…`) des fichiers propres à R8 et les citations historiques communes (Journal, docs) → parade `MAPPING-58.csv` + `MAPPING.csv`, sans réécrire les fiches (traces), comme ETAT-T2.
## 5. Transfert des sources de mods : `Tools\SyncModSources.ps1` (addon, proposé)
Emplacement : `Tools\SyncModSources.ps1` de l'addon (nouveau fichier ; `lot/DC3-atelier` puis `ue5.8`). Spécification : à blanc par défaut ; ne lit que `ModSources\<id>\Content` (ni `Saved\` résidus de cuisson, ni `Module\` / `.uplugin` suivis par git) ; ne supprime rien ; un fichier cible différent n'est remplacé qu'avec `-Overwrite`, après **déplacement** vers `D:\Game\LifePlay_Backup_5.5\<Lot>\…` ; refus si éditeur ouvert ou mod monté. Codes : 0 conforme ou copie contrôlée ; 1 écarts (à blanc, ou `DIFFERENT` laissés sans `-Overwrite`) ; 2 refus ; 3 MD5 faux après copie.
```powershell
<#
.SYNOPSIS
Copie controlee (MD5) des sources de mods hors git ModSources\<id>\Content d'un checkout de l'addon vers un
autre (ERR-046 : /ModSources/*/Content/ ignore par git, .gitignore:38, absent d'un nouveau worktree). A blanc par defaut.
.DESCRIPTION
Par mod : NOUVEAU (absent de la cible), IDENTIQUE, DIFFERENT, EN_TROP (cible seule), par chemin relatif et MD5.
-Apply : copie les NOUVEAU ; les DIFFERENT seulement avec -Overwrite (ancien fichier cible DEPLACE vers
<BackupRoot>\<Lot>\<horodatage>\...) ; EN_TROP signale, jamais touche ; MD5 relu sur la cible apres copie ;
rapport <BackupRoot>\<Lot>\sync_<horodatage>.csv. Refus : Source = Target, UnrealEditor ouvert, mod monte
(ModSources\<id>\<id>.uplugin absent d'un cote : voir Mount-ModSource de Tools\ModSource.ps1), Content source absent.
Codes : 0 conforme ou copie controlee ; 1 ecarts restants ; 2 refus ; 3 MD5 faux apres copie.
.EXAMPLE
.\Tools\SyncModSources.ps1 -Target D:\Game\LifePlay-Sandbox-5.8
.\Tools\SyncModSources.ps1 -Target D:\Game\LifePlay-Sandbox-5.8 -Id lpr_hair_pocolov -Apply
#>
param(
[string]$Source = 'D:\Game\LifePlay-Sandbox',
[Parameter(Mandatory)][string]$Target,
[string[]]$Id = @(),
[switch]$Apply,
[switch]$Overwrite,
[string]$Lot = 'SYNC-MODSOURCES',
[string]$BackupRoot = 'D:\Game\LifePlay_Backup_5.5'
)
$ErrorActionPreference = 'Stop'
function Stop-Sync([string]$Why) { Write-Host "SyncModSources : refus : $Why"; exit 2 }
$src = (Resolve-Path -LiteralPath $Source).Path.TrimEnd('\'); $dst = (Resolve-Path -LiteralPath $Target).Path.TrimEnd('\')
if ($src -eq $dst) { Stop-Sync 'Source = Target' }
$ed = Get-Process -Name 'UnrealEditor', 'UnrealEditor-Cmd' -ErrorAction SilentlyContinue
if ($ed) { Stop-Sync "UnrealEditor ouvert (PID $($ed.Id -join ', '))" }
if (-not $Id) { $Id = @(Get-ChildItem -LiteralPath (Join-Path $src 'ModSources') -Directory | Where-Object { Test-Path -LiteralPath (Join-Path $_.FullName 'Content') } | ForEach-Object Name) }
if (-not $Id) { Stop-Sync "aucun ModSources\<id>\Content dans $src" }
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$hash = { param($dir) $h = @{}; if (Test-Path -LiteralPath $dir) { Get-ChildItem -LiteralPath $dir -Recurse -File -Force | ForEach-Object { $h[$_.FullName.Substring($dir.Length + 1)] = (Get-FileHash -LiteralPath $_.FullName -Algorithm MD5).Hash } }; $h }
$rows = [System.Collections.Generic.List[object]]::new()
foreach ($m in $Id) {
foreach ($root in $src, $dst) {
if (-not (Test-Path -LiteralPath (Join-Path $root "ModSources\$m\$m.uplugin"))) { Stop-Sync "$root\ModSources\$m\$m.uplugin absent (mod monte, ou checkout sans ce mod)" }
}
$sc = Join-Path $src "ModSources\$m\Content"; $tc = Join-Path $dst "ModSources\$m\Content"
if (-not (Test-Path -LiteralPath $sc)) { Stop-Sync "$sc absent" }
$hs = & $hash $sc; $ht = & $hash $tc
foreach ($k in (@($hs.Keys) + @($ht.Keys) | Sort-Object -Unique)) {
$st = if (-not $ht.ContainsKey($k)) { 'NOUVEAU' } elseif (-not $hs.ContainsKey($k)) { 'EN_TROP' } elseif ($hs[$k] -eq $ht[$k]) { 'IDENTIQUE' } else { 'DIFFERENT' }
$rows.Add([pscustomobject]@{ Mod = $m; Rel = $k; Etat = $st; MD5Source = $hs[$k]; MD5Cible = $ht[$k]; Action = '' })
}
}
if ($Apply) {
foreach ($r in @($rows | Where-Object { $_.Etat -eq 'NOUVEAU' -or ($_.Etat -eq 'DIFFERENT' -and $Overwrite) })) {
$from = Join-Path $src "ModSources\$($r.Mod)\Content\$($r.Rel)"; $to = Join-Path $dst "ModSources\$($r.Mod)\Content\$($r.Rel)"
if ($r.Etat -eq 'DIFFERENT') {
$bk = Join-Path $BackupRoot "$Lot\$stamp\$(Split-Path $dst -Leaf)\ModSources\$($r.Mod)\Content\$($r.Rel)"
New-Item -ItemType Directory -Force (Split-Path $bk -Parent) | Out-Null
Move-Item -LiteralPath $to -Destination $bk
}
New-Item -ItemType Directory -Force (Split-Path $to -Parent) | Out-Null
Copy-Item -LiteralPath $from -Destination $to
$r.MD5Cible = (Get-FileHash -LiteralPath $to -Algorithm MD5).Hash
$r.Action = if ($r.MD5Cible -eq $r.MD5Source) { 'copie OK' } else { 'copie MD5 KO' }
}
$rep = Join-Path $BackupRoot "$Lot\sync_$stamp.csv"
New-Item -ItemType Directory -Force (Split-Path $rep -Parent) | Out-Null
$rows | Export-Csv -LiteralPath $rep -NoTypeInformation -Encoding UTF8
Write-Host "rapport : $rep"
}
$rows | Group-Object Mod, Etat | Sort-Object Name | ForEach-Object { '{0,-45} {1,5}' -f $_.Name, $_.Count }
if ($rows | Where-Object Action -eq 'copie MD5 KO') { exit 3 }
$left = @($rows | Where-Object { ($_.Etat -eq 'NOUVEAU' -and -not $Apply) -or ($_.Etat -eq 'DIFFERENT' -and -not ($Apply -and $Overwrite)) })
if ($left) { Write-Host "$($left.Count) fichier(s) a copier ou a arbitrer (-Apply, -Overwrite)"; exit 1 }
exit 0
```
Résultat attendu aujourd'hui (établi par le § 1.4) : `-Target D:\Game\LifePlay-Sandbox-5.8` à blanc → 3 mods, `IDENTIQUE` 20 + 84 + 70 = 174, 0 autre, code 0.
## 6. Plan en étapes (ordre, niveaux, filets)
Filets communs : `Tools\Snapshot.ps1 -Lot <lot> -Path <fichiers>` avant toute écriture (manifeste MD5, `Existed=False` pour un fichier nouveau ; `Restore.ps1` pour revenir) ; tag git local `ETAT2-avant` sur chaque branche touchée avant le premier commit ; rien n'est poussé ; aucune suppression (déplacement vers `D:\Game\LifePlay_Backup_5.5\<lot>\`).
**Phase A — possible tout de suite (ne touche ni la copie 5.8 ni `A58`)**
| # | Fiche | Niveau / modèle | Contenu | Critère de sortie |
|---|---|---|---|---|
| A1 | ETAT2-T2-IMPL (jeu 5.5, `main`) | N2 / Sonnet | `Snapshot.ps1 -Lot ETAT2 -Path Tools\RunCommandlet.ps1,Tools\ReimportCorrectif.ps1,Tools\AssetHeaders.ps1,Tools\EtatDir.ps1` ; tag `ETAT2-avant` ; créer `EtatDir.ps1` (§ 2.2) ; appliquer les diffs § 2.3 ; pas de commit | `git diff --stat` = 3 modifiés + 1 nouveau |
| A2 | ETAT2-T3-VAL (5.5) | N2 / Sonnet | analyse syntaxique (`[System.Management.Automation.Language.Parser]::ParseFile`, 0 erreur ×4) ; table § 2.2 avec `-NoCreate` (22 cas) ; `git diff -U0 \| Select-String Remove-Item` = 0 ligne ; `Select-String -- '-EtatDir \$etat'` = 5 dans `ReimportCorrectif.ps1` ; racine `R5` toujours 5 fichiers. **Essai réel de commandlet reporté en phase B** (`Build.ps1:55`, § 1.1) sauf accord (D13) | PASS / FAIL chiffré |
| A3 | commit `main` (orchestrateur, N0) | — | un seul commit « ETAT2 : preuves des scripts dans etat/<projet>/<lot>/ (Tools/EtatDir.ps1) » ; n° CHG réservé (D14), entrée de Journal écrite en B5 | `git log -1` |
| A4 | ETAT2-T4-IMPL (addon `A55`, `lot/DC3-atelier`) | N2 / Sonnet | `Snapshot.ps1 -Lot ETAT2-addon -ProjectRoot D:\Game\LifePlay-Sandbox -Path <11 skills + Tools\SyncModSources.ps1>` ; tag `ETAT2-avant` ; texte § 3 ; script § 5 | `git -C A55 diff --stat` |
| A5 | ETAT2-T5-VAL (addon) | N2 / Sonnet | relecture caractère par caractère des passages § 3 ; `SyncModSources.ps1 -Target A58` à blanc = 174 `IDENTIQUE`, code 0 (lecture seule de `A58`) ; essai positif dans `D:\Game\LifePlay_Backup_5.5\ETAT2\sync-test\` (copie des seuls `ModSources\<id>\<id>.uplugin`) : à blanc 174 `NOUVEAU`, code 1 → `-Apply` 174 copiés, MD5 174/174 → à blanc 174 `IDENTIQUE`, code 0 ; un fichier altéré à la main dans la cible d'essai → `DIFFERENT` 1, code 1 → `-Apply -Overwrite` : ancien déplacé dans `Backup_5.5\SYNC-MODSOURCES\…`, code 0 | PASS / FAIL |
| A6 | commit addon (orchestrateur) | — | commit sur `lot/DC3-atelier` ; pin du jeu mis à jour en B5 (doc 21 vit sur `ue5.8`) | `git log -1` |
A1-A3 et A4-A6 sont indépendants (deux dépôts) et peuvent être menés en parallèle.
**Porte G-STM-FIN (avant toute action en phase B)** : la session STM a commité (CHG-260 dans `git log` de `ue5.8`) ; `git -C "D:\Game\LifePlay-master 5.8" status --porcelain` vide ; aucun processus `UnrealEditor`, `UnrealEditor-Cmd` ; `find R8 -maxdepth 1 -newermt <fin de session>` vide ; accord de l'utilisateur.
**Phase B — après la fin de la session STM**
| # | Fiche | Niveau / modèle | Contenu | Critère |
|---|---|---|---|---|
| B1 | ETAT2-T6-IMPL (jeu 5.8, `ue5.8`) | N2 / Sonnet | `Snapshot.ps1 -Lot ETAT2-58 -Path Tools\RunCommandlet.ps1,Tools\ReimportCorrectif.ps1,Tools\Build.ps1,Tools\AssetHeaders.ps1,Tools\EtatDir.ps1` ; tag `ETAT2-avant` ; `git fetch "D:\Game\LifePlay-master 5.5" main:refs/remotes/c55/main` puis `git cherry-pick <commit A3>` (attendu sans conflit, § 2.3) ; second commit `Build.ps1` | cherry-pick sans conflit, sinon arrêt et rapport |
| B2 | ETAT2-T7-VAL (5.8) | N2 / Sonnet | mêmes contrôles qu'A2 ; `Build.ps1 -Lot ETAT2 -FromLog Saved\Logs\portage\U7_Build_20261009-103224.log` → `R8\ETAT2\ETAT2_BuildLog_*.txt` (ni compilation ni moteur) ; `RunCommandlet.ps1 -Lot ETAT2 -Commandlet LPTestStringCompat` → `R8\ETAT2\…` avec `3120 cas`, `compat … : 0`, code 0 ; idem en 5.5 → `R5\ETAT2\…` ; racine R8 inchangée pendant l'essai | PASS / FAIL |
| B3 | ETAT2-T8-REORG (R8) | N1 / Sonnet (comme ETAT-T2) | `Snapshot.ps1 -Lot ETAT2-R8 -Path Docs\Migration\etat -Recurse` dans la copie 5.8 (lancé par `pwsh -Command`, piège ETAT-T2 n° 1) → manifeste attendu 472 + STM + essais B2 ; générer `R8\MAPPING-58.csv` à blanc (360 lignes + STM ; 0 doublon de cible) ; déplacements internes (D9) ; MD5 de chaque fichier déplacé contre le manifeste ; recompte (racine = `L0_ref427.csv` + `MAPPING-58.csv`) | MD5 360/360 (+ STM) OK |
| B4 | ETAT2-T9 (addon `A58`, `ue5.8`) | N1 | selon D11 : `git cherry-pick` des commits A6 (skills + script) sur `ue5.8` | sans conflit, sinon arrêt |
| B5 | ETAT2-DOC (orchestrateur, N0) | — | Journal `ue5.8` (CHG réservé), Registre ERR-046 → « corrigé (script SyncModSources) », doc 21 l. 217 coché + pin addon, docs 03:109 et 09:61, `R5\INVENTAIRE.md` § 4 (conventions) et § 6 (R8 réorganisée), mémoire `lifeplay-build-pitfalls.md:15` ; commits par phase, rien poussé | relecture |
Dépendances : A3 avant B1 (cherry-pick) ; A6 avant B4 ; B1-B2 avant B3 (les scripts 5.8 cessent d'écrire à la racine avant qu'on la vide) ; B3 avant B5.
## 7. Décisions à soumettre à l'utilisateur (liste fermée, recommandation en premier)
- **D1 Convention** : (a) `Tools\EtatDir.ps1` (table lot → projet) + `-EtatDir` ; (b) `-EtatDir` seul, défaut racine ; (c) `-EtatDir` obligatoire.
- **D2 Lot hors table** : (a) `etat\<Lot>\` + avertissement ; (b) racine + avertissement (rétrocompatible strict) ; (c) erreur bloquante.
- **D3 Documents des lots ETAT** : (a) `etat\ETAT2\` à plat (comme ce livrable), `ETAT-INVENTAIRE-PROPOSITION.md` et `ETAT-T2-REORG.md` laissés à la racine ; (b) ces deux documents déplacés dans `etat\ETAT\` (`INVENTAIRE.md`, `MAPPING.csv` restent à la racine).
- **D4 Branches du jeu** : (a) un commit `main` puis `cherry-pick` sur `ue5.8` + commit `Build.ps1` ; (b) éditions séparées par branche ; (c) `ue5.8` seulement (`main` reçoit à la fusion V2.0).
- **D5 `Remove-Item` de `ReimportCorrectif.ps1`** : (a) inchangés en ETAT2 (portée réduite au dossier du lot) ; (b) remplacés par un déplacement vers `Backup_5.5\<Id>\` dans un lot séparé.
- **D6 `etat` 5.8** : (a) réorganisé comme R5 avec `MAPPING-58.csv` (360 déplacements) ; (b) les 422 doublons (283 + 139, MD5 identiques à R5) déplacés vers `Backup_5.5\ETAT2-R8\`, seuls les 49 propres à R8 rangés ; (c) laissé tel quel.
- **D7 Les 49 fichiers propres à R8** : (a) restent dans R8 ; (b) copiés aussi dans `R5\U58\<lot>\`.
- **D8 `L0_ref427.csv` de R8** : (a) reste à la racine (symétrie avec R5) ; (b) vers `portage55\L0\` (aucun lecteur sur `ue5.8`).
- **D9 Mode de déplacement dans R8** : (a) `Move-Item` interne après instantané, comme ETAT-T2 ; (b) copie puis archivage des originaux dans `Backup_5.5`.
- **D10 Transfert des sources de mods** : (a) script `Tools\SyncModSources.ps1` + ligne `lp-paths` ; (b) section de skill seule (commandes manuelles).
- **D11 Skills de la branche `ue5.8` de l'addon** : (a) mettre à jour `lot/DC3-atelier` (actif) en phase A, porter sur `ue5.8` en B4 ; (b) les deux en phase A ; (c) `lot/DC3-atelier` seulement.
- **D12 Gabarits figés sur `U58`** (`lp-build:115`, `lp-validate:14`, `:83`) : (a) généraliser en `<projet>` ; (b) laisser.
- **D13 Essais réels en 5.5 pendant STM** : (a) non, essais statiques en A2, essais réels en B2 ; (b) oui, `LPTestStringCompat` 5.5 (16 s environ en 5.8) avec accord, au risque d'un code 3 dans un `Build.ps1` de la session STM.
- **D14 Numéro de CHG** : (a) premier numéro libre après la clôture de STM, entrée écrite en B5 ; (b) numéro réservé maintenant auprès de la session STM.
## 8. Compte rendu sk-protocol
[sk-protocol] Skills présents dans le contexte : sk-protocol, lp-paths, lp-commandlets, ue-cpp-build (lp-build cité par la fiche mais non chargé).
1. **Résultat** : réussi — cartographie complète, convention unique, diffs, mapping 5.8 et script proposés ; rien modifié hors de ce fichier.
2. **Preuves** : lignes citées § 1 (`grep -n` rejoués, lecture intégrale de `RunCommandlet`, `ReimportCorrectif`, `CheckIntegrity`, `Build`, `Engine`, `ModSource`) ; MD5 R8/R5 et addon (`md5sum`, scripts du dossier temporaire de session).
3. **Chiffres** : R5 racine 5 / total 616 ; R8 racine 333 / total 472 / sous-dossiers 139 (deux méthodes) ; R8 = 283 + 1 + 49 racine, 139/139 identiques ; 360 déplacements proposés ; 49 = AP7 3, U2 1, U3 5, U4 3, U5 13, U7 14, U7b 8, STM 2 ; 60 citations / 34 noms / 21 fiches ; ModSources 174/174 identiques, 88 888 626 octets.
4. **Incertitudes** : expressions de `EtatDir.ps1` et absence de conflit au `cherry-pick` estimées, non exécutées (essais A2, B1) ; la session STM ajoutera des fichiers `STM_*` après ce relevé.
5. **Écarts** : `lp-build` non préchargé ; dossier `R5\ETAT2\` créé ; fichier écrit : `D:\Game\LifePlay-master 5.5\Docs\Migration\etat\ETAT2\ETAT2-T1-CART.md` ; fichiers temporaires dans le dossier temporaire de session seulement.
6. **Suite** : l'orchestrateur doit faire trancher D1-D14, puis lancer A1/A4 (5.5 et addon) ; la phase B attend la porte G-STM-FIN ; état : cartographie livrée, aucun script ni dossier `etat` modifié.