LifePlay-Revival/Docs/Migration/etat/OUTC/OUTC-T2-IMPL.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

111 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Fiche OUTC-T2 — Niveau N1 — Modèle prévu sonnet | utilisé claude-sonnet-5-5 — Agent lp-impl — Skills sk-protocol (préchargé), sk-windows-shell (invoqué), sk-repo § 2 et § 6 et lp-repo § 7 (lus par Read), ue-cpp-build / lp-build / lp-ue-compat (préchargés, sans objet)
# OUTC-T2-IMPL : `Tools\Verrou.ps1` et `Tools\Numero.ps1` (2026-10-11)
Résultat : réussi, avec **un écart de moyen à décider** (§ 2 E1 : création du dossier de verrou par `CreateDirectoryW` et non par `New-Item`, parce que `New-Item` sans `-Force` n'est pas atomique, mesure à l'appui). Essais : 124 appels et contrôles, 0 écart (`SYNTHESE` de `OUTC-T2_essais.txt` l. 417) ; vrai `VERROU` lu en `-Etat` seulement ; vrai `NUMEROS.md` jamais écrit.
## 1. Fichiers modifiés (chemins, lignes)
Dépôt du jeu `D:\Game\LifePlay-master 5.8`, branche `ue5.8`, HEAD `ae5d5e4` (la fiche citait `06dfb55` : le HEAD a avancé, sans effet sur ces fichiers). Les deux sont neufs, LF, sans BOM, ASCII seul (`FileCheck.ps1` : `LF`, `CRLF=0`, `BOM -`, alertes 0 ; octets > 0x7F = 0 ; analyse syntaxique pwsh : 0 erreur).
| Fichier | Lignes | Taille | MD5 | Contenu |
|---|---|---|---|---|
| `Tools\Verrou.ps1` | 228 | 11 010 o | `788B21F30155200A497C3919FB3CBA29` | en-tête d'aide l. 1-58 ; `param` l. 59 ; `New-DossierAtomique` l. 75 ; `Get-VerrouK` l. 86 ; `Get-Qui` l. 99 ; `Fin` l. 123 ; `New-LignesOccupe` l. 130 ; `-Prendre` l. 157 ; `-Rendre` l. 190 ; `-Etat` l. 216 ; `catch` général (code 2) l. 225 |
| `Tools\Numero.ps1` | 291 | 13 849 o | `8803E6A42DAD21292DFE3024732BF589` | en-tête d'aide ; `param` l. 63 ; `Get-MaxFichier` l. 85 ; `Get-MaxDocs` l. 100 ; `Get-MaxRegistre` l. 116 ; `Get-Maxima` l. 134 ; usage l. 168 ; `-Dernier` l. 178 ; `-Reserver` l. 194 ; `try` l. 220 ; `catch` l. 270 ; `finally` (rend le verrou) l. 273 |
Comportement livré (conforme à `OUTC-SPEC.md` § 3.2 et § 3.3 sauf § 2) :
- `Verrou.ps1 -Prendre <ticket> [-Session] | -Rendre [-Ticket] | -Etat`, `-Racine` (défaut `<projet>\Docs\Migration\etat\REPO\VERROU`), `-Json`. Codes 0 / 1 / 2 comme la SPEC. Rien n'est supprimé ni renommé, aucun paramètre de forçage ; au-delà de 30 min, suffixe `ANCIEN (signaler, ne pas forcer)`.
- `Numero.ps1 -Reserver CHG|ERR|DOC -Lot -Demandeur [-Nombre] [-Copie55] [-Fichier] [-Racine] [-Json]` et `-Dernier CHG|ERR|DOC`. Écriture par ajout d'octets (`FileStream` en `Append`), séparateur détecté, contrôle du préfixe (MD5 des `n` octets d'avant), de la longueur et de la fin ; verrou rendu dans un `finally`.
## 2. Écarts à la SPEC (obligatoire)
- **E1 (à décider) — moyen de création du dossier de verrou.** SPEC § 3.2 point 2 et fiche § 5 prescrivent `New-Item -ItemType Directory` sans `-Force`, « échoue si le dossier existe ». Vrai en séquentiel, **faux en concurrence** : essai en 100 tours de 8 threads alignés sur une `Threading.Barrier`, tous appelant `New-Item -ItemType Directory -Path <même chemin> -ErrorAction Stop` (pwsh 7.6.6) : **exactement 1 succès dans 12 tours, plusieurs succès dans 88 tours**, 0 tour sans succès (sortie de la commande, tour 9 de cette fiche ; commande rappelée ci-dessous). Même essai avec `CreateDirectoryW` de `kernel32` (P/Invoke par `Add-Type`) : **1 succès dans 100 tours sur 100** ; second appel séquentiel : `False`, `GetLastWin32Error` = 183 (`ERROR_ALREADY_EXISTS`) (`scratchpad\OUTC-T2\stress2.ps1`, sortie dans ce compte rendu). Avec `New-Item`, deux gardiens pourraient donc se croire titulaires du même `k+1`, ce que le verrou doit empêcher. **Choix fait** : `New-DossierAtomique` (`Verrou.ps1` l. 75-84) appelle `CreateDirectoryW` ; 183 = occupé (code 1), autre erreur = code 2. Effet de bord : `Add-Type` coûte ≈ 640 ms au premier appel de chaque processus. Retour à la lettre de la SPEC : remplacer le corps de cette seule fonction par `try { New-Item -ItemType Directory -Path $Path -ErrorAction Stop | Out-Null; $true } catch { if (Test-Path -LiteralPath $Path) { $false } else { throw } }` ; je ne le recommande pas. Preuve en processus séparés (A17) : 5 tours de 6 processus `Verrou.ps1 -Prendre` lancés ensemble : à chaque tour un seul code 0, cinq codes 1, `qui.txt` du dossier = celui du gagnant (l. 184-204 de `OUTC-T2_essais.txt`).
Commande de l'essai `New-Item` (non rangée en fichier, rejouable) : `pwsh -NoProfile -Command` avec `foreach ($r in 1..100) { $p = Join-Path $base "r$r"; $bar = [Threading.Barrier]::new(8); $res = 1..8 | ForEach-Object -Parallel { $b = $using:bar; $path = $using:p; $b.SignalAndWait(); try { New-Item -ItemType Directory -Path $path -ErrorAction Stop | Out-Null; 1 } catch { 0 } } -ThrottleLimit 8; ... somme des 1 par tour }`.
- E2 — course simulée : paramètre caché `-TestCourse` (`[Parameter(DontShow)]`, décrit dans l'aide) : juste avant la création, crée le dossier cible comme le ferait un tiers (avec `qui.txt` `TIERS-TEST` pour `-Prendre`). Prévu par la fiche (« paramètre caché de test, à décrire »).
- E3 — affichage d'un verrou occupé : première ligne `qui.txt (k=<k>) : <contenu brut>`, dernière ligne `VERROU OCCUPE k=<k> par <qui> depuis <min> min`, où `<qui>` = `qui.txt` sans la date finale. `-Etat` n'imprime que la ligne de verdict. La SPEC dit « affiche `<k>\qui.txt` » sans préciser le format. Refus de `-Rendre -Ticket` : `VERROU REFUS k=<k> : tenu par <qui>, pas par <ticket>` (libellé non fixé par la SPEC).
- E4 — `-Rendre -Ticket T` : correspondance = `qui.txt` commence par `T` **suivi d'un caractère autre que lettre, chiffre, `_` ou `-`** (ou fin de ligne), insensible à la casse ; la SPEC dit « commence par ce ticket », ce qui ferait rendre le verrou de `OUTC-R10` à `OUTC-R1` (essais A11b, A11c).
- E5 — points laissés ouverts par la SPEC, tranchés : sans `-Session`, `qui.txt` porte `session non precisee` ; `-Ticket` sans `-Rendre` et `-Session` sans `-Prendre` = paramètres incohérents, code 2 ; racine vide = `k` 0, libre ; `-Rendre` sans `-Ticket` rend le verrou tenu, quel qu'en soit le titulaire (SPEC § 3.2 point 3 ne demande le contrôle qu'avec `-Ticket`).
- E6 — `-Json` accepté par les trois actions de `Verrou.ps1` (la SPEC ne le cite que pour `-Etat`) : `Numero.ps1` en a besoin pour lire `k` et le code.
- E7 — `Numero.ps1`, format : date `AAAA-MM-JJ HH:MM` (heure locale ; la SPEC montre `AAAA-MM-JJ`, la fiche § 5 prescrit `Get-Date -Format 'yyyy-MM-dd HH:mm'`, comme les lignes existantes) ; plusieurs numéros : `NUMERO RESERVE CHG-330 CHG-331 lot=TEST verrou=5` ; JSON : `type`, `numeros[]` (entiers), `ids[]` (`CHG-330`), `lot`, `demandeur`, `verrou`, `fichier`, `date`, `maxima{copie58, copie55, registre, max}`, `avertissements[]` (la SPEC liste `{type, numeros[], lot, verrou, maxima{}}`, ces ajouts sont rétrocompatibles) ; `-Dernier` : `DERNIER CHG max=327 5.8=326 5.5=297 registre=327`.
- E8 — cas non couverts par la SPEC : source 5.8 absente ou sans numéro = code 2 (jamais « max = 0 ») ; copie 5.5 absente = avertissement et `5.5=absent` dans la ligne ; `-Nombre` hors 1..50 = code 2 ; `|` du lot ou du demandeur remplacé par `/`, sauts de ligne par un blanc ; session du verrou = demandeur tronqué à 80 caractères, ticket `NUMERO-<LOT>` ; fichier vide ou sans aucun saut de ligne = code 2 **après** la prise du verrou (le verrou est rendu : essais B6a, B6b) ; fichier à fins de ligne mixtes = avertissement, séparateur du dernier saut de ligne retenu ; verrou non rendu après une réservation réussie = ligne `VERROU NON RENDU` et code 2.
- E9 — le livrable `OUTC-T2_essais.txt` demandé par la fiche est ignoré par git (`.gitignore:75 /Docs/Migration/etat/**`, seuls `.md` et `.csv` sont repris, l. 77) : il reste sur disque, hors « Fichiers à commiter ».
## 3. Instantané (lot, manifeste)
Lot `OUTC` : `D:\Game\LifePlay-master 5.8` instantané `D:\Game\LifePlay_Backup_5.5\OUTC\manifest.csv` (2026-10-11 06:26) ; les deux fichiers y sont `Existed=False`, `Size=0` (lu l. 3-4 du manifeste) : rien à restaurer, le repli est « ne pas commiter / retirer les deux fichiers neufs » (`Tools\Restore.ps1 -Lot OUTC`, proposé, non lancé).
## 4. Ce qui n'a pas été fait
- Aucun essai en écriture sur le vrai `VERROU` ni sur le vrai `NUMEROS.md` (interdit). Le vrai verrou n'a été lu que par `Verrou.ps1 -Etat` (A18, série officielle : `VERROU LIBRE k=93`, 186 dossiers, liste identique avant / après l'appel) et par `Get-ChildItem`. Le vrai `NUMEROS.md` n'a été lu que par `Numero.ps1 -Dernier` (B1r) et `Get-FileHash` ; MD5 `CD7800199276A0AB4F2019D4044816DF` au début, à la copie et à la fin de la série.
- Pas d'essai de concurrence **entre processus** pour `Numero.ps1` (fait pour `Verrou.ps1`, A17) : l'exclusion repose sur `Verrou.ps1`.
- Windows PowerShell 5.1 : 6 commandes seulement (§ D du fichier d'essais : `Verrou` `-Etat`, `-Prendre`, occupé, `-Rendre -Ticket` ; `Numero` `-Dernier`, `-Reserver`), codes attendus, puis `FileCheck` de la copie sous pwsh 7 ; pas la série complète.
- Pas d'essai d'erreur de droits d'écriture ni de fichier verrouillé par un autre processus.
- Pas de mise à jour de `sk-repo` § 2 ni de `lp-repo` § 7 (qui décrivent encore `mkdir` et la lecture manuelle) : lot DOC séparé (SPEC § 5, décision E5).
- Aucun autre fichier de `Tools\` touché ; pas de commit, pas de git en écriture, aucune suppression.
## 5. Points à confirmer en VAL
- E1 : l'orchestrateur confirme `CreateDirectoryW` (recommandé) ou demande le retour à `New-Item` ; la VAL peut rejouer `scratchpad\OUTC-T2\stress2.ps1 -Base <dossier neuf>` (attendu : `exactement 1 succes=100`).
- V7 rejoué : Prendre (0), Prendre encore (1), Etat (1), Rendre -Ticket autre (1), Rendre (0), Rendre encore (1), Etat (0) = essais A2 à A8 (`essais.ps1` du scratchpad, `-Base` neuf obligatoire : le script refuse une base où `VERROU` existe).
- V7 course : `-TestCourse` rend 1 pour `-Prendre` et pour `-Rendre`, le `qui.txt` du tiers n'est pas écrasé (A12, A13).
- V8 rejoué : `Numero.ps1 -Reserver CHG -Lot TEST -Fichier <copie> -Racine <test>` deux fois puis `-Nombre 2` : numéros consécutifs 328, 329, 330-331 ; préfixe de 12 601 octets de MD5 identique ; `FileCheck` : `CRLF`, `LF=0`, `CR=0` (B2, B4) ; verrou occupé = code 1, MD5 entier inchangé (B5).
- Le format de la ligne ajoutée (statut `réservé` avec accents UTF-8 ; date avec heure) convient au gardien et à `lp-repo` § 7.
- `-Rendre` sans `-Ticket` (E5) : acceptable pour le gardien, ou exiger `-Ticket`.
- Coût de ≈ 640 ms d'`Add-Type` par appel de `Verrou.ps1` acceptable (≈ 1 085 appels de verrou en 72 h d'après la SPEC).
- À la DOC (T5), `Numero.ps1 -Reserver CHG` réel sans `-Fichier` ni `-Racine` : le défaut est le vrai `NUMEROS.md` et le vrai `VERROU` ; à ce jour (06:44) le registre réel donne `max=327` (`CHG-326` et `CHG-327` posés par d'autres sessions depuis la rédaction de la fiche).
## 6. Fichiers à commiter
Dépôt du jeu `D:\Game\LifePlay-master 5.8`, branche `ue5.8` :
- A `Tools/Verrou.ps1`
- A `Tools/Numero.ps1`
- A `Docs/Migration/etat/OUTC/OUTC-T2-IMPL.md`
Non commités : `Docs/Migration/etat/OUTC/OUTC-T2_essais.txt` (ignoré, `.gitignore:75`) ; scratchpad `<scratchpad>\OUTC-T2\` (`essais.ps1`, `stress2.ps1`, racines et copies de test `VERROU*`, `NUMEROS-test.md`, `NUM-*.md`, essais de mise au point `dev1`, `dev2`, `stress`, `stress2`, sorties `dev1.txt`, `dev2.txt` ; rien supprimé). `essais.ps1` est réutilisable par la VAL : à ranger dans `Saved\OUTC\` ou à copier, selon `sk-protocol` § 7.
## Table des essais (commande → code → sortie)
Sorties brutes complètes : `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\OUTC\OUTC-T2_essais.txt` (76 appels `>>>` / `<<<`, dont 7 de la section D lancés à la main hors du script, + 55 contrôles `CHECK`, tous OK ; les 124 de `SYNTHESE` = 69 appels comptés par le script + 55 contrôles). Racine de test `…\scratchpad\OUTC-T2\VERROU` (départ `1 1-libre 2 2-libre`, k = 2). Toutes les commandes sont `pwsh -NoProfile -File <script> …`.
| Id | Commande (abrégée) | Code | Sortie / dossiers |
|---|---|---|---|
| A1 | `Verrou -Etat` | 0 | `VERROU LIBRE k=2` |
| A2 | `Verrou -Prendre OUTC-T2-A -Session "essai Verrou"` | 0 | `VERROU PRIS k=3 ticket=OUTC-T2-A` ; dossier `3`, `qui.txt` = `OUTC-T2-A, session essai Verrou, 2026-10-11 06:44`, LF seul |
| A3 | `Verrou -Prendre OUTC-T2-B` | 1 | `VERROU OCCUPE k=3 par OUTC-T2-A, session essai Verrou depuis 0 min` ; `qui.txt` inchangé |
| A4 | `Verrou -Etat` | 1 | `VERROU OCCUPE k=3 par …` |
| A5 | `Verrou -Rendre -Ticket AUTRE-TICKET` | 1 | `VERROU REFUS k=3 : tenu par OUTC-T2-A, …` ; pas de `3-libre` |
| A6 | `Verrou -Rendre -Ticket OUTC-T2-A` | 0 | `VERROU RENDU k=3` ; `3-libre` créé |
| A7 | `Verrou -Rendre` | 1 | `VERROU DEJA LIBRE k=3` |
| A8 | `Verrou -Etat` | 0 | `VERROU LIBRE k=3` ; dossiers `1 1-libre 2 2-libre 3 3-libre` |
| A9-A11 | sans `-Session` ; `-Etat -Json` ; `-Prendre OUTC-R10` puis `-Rendre -Ticket OUTC-R1` (1) puis `-Ticket outc-r10` (0) ; `-Prendre -Json` (0 puis 1) | 0 / 1 | `session non precisee` ; JSON valide (`etat`, `k`, `code`) ; R1 ne rend pas R10 |
| A12 | `Verrou -Prendre OUTC-T2-X -TestCourse` | 1 | `qui.txt (k=7) : TIERS-TEST, session essai de course …` ; dossier `7` créé par le « tiers », son `qui.txt` non écrasé, aucun `qui.txt` `OUTC-T2-X` ; `-Etat` 1 ; `-Rendre -Ticket TIERS-TEST` 0 |
| A13 | `Verrou -Rendre -TestCourse` (tiers crée `8-libre` avant nous) | 1 | `VERROU DEJA LIBRE k=8` ; `-Etat` 0 |
| A14 | aucune action ; deux actions ; `-Ticket` avec `-Etat` ; `-Session` avec `-Etat` ; racine introuvable ; `-Prendre ""` | 2 (×6) | messages `Verrou.ps1 : …` ; dossiers inchangés |
| A15 | racine avec `2` daté de 45 min : `-Etat` ; `-Prendre` | 1 / 1 | `… depuis 45 min ANCIEN (signaler, ne pas forcer)` ; rien forcé |
| A16 | `9 9-libre 10` : `-Etat` ; `10 10-libre 9 9-libre` : `-Etat` ; racine vide : `-Etat`, `-Rendre`, `-Prendre` | 1 / 0 / 0 / 1 / 0 | `k=10` (tri numérique) ; `k=0` ; `PRIS k=1` |
| A17 | 5 tours × 6 processus `Verrou -Prendre P<t>-<i>` lancés ensemble | 0 ×1 + 1 ×5 par tour | gagnants `P1-2, P2-2, P3-1, P4-1, P5-1` ; `qui.txt` = celui du gagnant ; `-Rendre -Ticket <gagnant>` 0 à chaque tour |
| A18 | `Verrou -Etat` (vrai VERROU, sans `-Racine`) | 0 | `VERROU LIBRE k=93` ; 186 dossiers avant et après l'appel, listes identiques |
| B1 | `Numero -Dernier CHG|ERR|DOC -Fichier <copie>` ; `-Json` ; vrai fichier par défaut ; plage `150 à 190` | 0 | `max=327 (5.8=326 5.5=297 registre=327)`, `max=88`, `max=33` = maxima recalculés par un autre code (`Select-String`) ; plage : `registre=190` (borne haute) ; aucun dossier de verrou créé |
| B2a | `Numero -Reserver CHG -Lot TEST -Demandeur essai -Fichier <copie> -Racine <VERROU-NUM>` | 0 | `NUMERO RESERVE CHG-328 lot=TEST verrou=3` |
| B2b | idem | 0 | `NUMERO RESERVE CHG-329 lot=TEST verrou=4` |
| B2c | idem `-Nombre 2` | 0 | `NUMERO RESERVE CHG-330 CHG-331 lot=TEST verrou=5` ; dossiers `1 1-libre … 5 5-libre` |
| B3 | `-Reserver ERR` ; `DOC` ; `CHG -Json` (demandeur avec `|`) ; `CHG -Copie55 <absente>` ; `DOC` avec accents | 0 ×5 | `ERR-089`, `DOC-34`, `CHG-332` (JSON valide, `demandeur` = `essai / avec pipe`), `CHG-333` + `AVERTISSEMENT : copie 5.5 absente …` et `5.5=absent`, `DOC-35` (UTF-8 valide) |
| B4 | contrôles sur la copie après 8 appels | — | préfixe : 12 601 octets, MD5 avant = après `CD7800199276A0AB4F2019D4044816DF` ; longueur 12 601 → 13 664 ; 9 lignes ajoutées, toutes au format SPEC, CRLF, 0 LF seul, pas de BOM ; `FileCheck` : `CRLF`, `LF=0`, `CR=0`, alertes 0 |
| B5 | `-Reserver CHG` avec verrou `2` occupé par un tiers | 1 | `NUMERO REFUSE : verrou occupe (…) ; rien n'a ete ecrit` ; MD5 entier de la copie et liste du verrou inchangés |
| B6 | fichier sans saut de ligne ; fichier vide ; fichier introuvable | 2 ×3 | erreur nommée ; verrou pris puis **rendu** (`2-libre`, `3-libre`) pour les deux premiers ; aucun verrou pris pour le troisième ; fichiers non modifiés |
| B7 | fichier LF sans saut final ; fichier CRLF sans saut final | 0 ×2 | `CHG-327` ; LF conservé (LF seul 6, CRLF 0) ; CRLF conservé (CRLF 6, LF seul 0) ; préfixe identique |
| B8 | pas de type ; deux types ; type inconnu ; `-Lot` ou `-Demandeur` manquant ; `-Nombre 0` ; racine de verrou introuvable | 2 ×7 | messages d'usage ; aucun verrou pris ; copie inchangée |
| C | vrai `NUMEROS.md` / vrai `VERROU` après la série | — | MD5 réel inchangé `CD78…` ; aucune ligne `TEST` dans le vrai fichier ; 1 dossier apparu dans le vrai `VERROU` (`93-libre`, autre session), aucun ticket des essais |
| D | `powershell.exe` 5.1.26100.9549 : `Verrou -Etat` ; `-Prendre PS51-A` ; `-Prendre PS51-B` ; `-Rendre -Ticket PS51-A` ; `Numero -Dernier CHG` ; `-Reserver CHG -Lot TEST51` ; puis `FileCheck` (pwsh 7) | 0 / 0 / 1 / 0 / 0 / 0 / 0 | `PRIS k=2` ; `OCCUPE k=2` ; `RENDU k=2` ; `DERNIER CHG max=333 …` ; `NUMERO RESERVE CHG-334 lot=TEST51 verrou=3` ; copie `CRLF`, `LF=0`, alertes 0 |
Commande rejouable de la série complète : `pwsh -NoProfile -File "…\scratchpad\OUTC-T2\essais.ps1" -Base <dossier neuf>` (garde interne : tout appel qui écrit exige `-Racine` et `-Fichier` sous `-Base`).
Tours : 26 / 40 (compte propre, à confirmer par `python -I Tools/FicheStats.py --lot OUTC` ; la fiche demande 40, le plafond de l'agent est 75)
## Constats
1. **`New-Item` n'est pas atomique** (E1) : l'hypothèse de `sk-repo` § 2 / de la SPEC (« `mkdir` échoue si le dossier existe, opération atomique ») est vraie pour `cmd mkdir` et `CreateDirectoryW`, pas pour `New-Item` de PowerShell. Un gardien qui poserait le verrou à la main par `New-Item` (et non par `mkdir` de cmd ou par `Verrou.ps1`) hériterait du même défaut ; à noter pour le lot DOC qui réécrira `sk-repo` § 2.
2. Le vrai `NUMEROS.md` a changé pendant l'IMPL (11 885 octets à ma première lecture, avec `CHG-326` ; 12 601 octets à 06:41, avec `CHG-327` ; réservations d'autres sessions) : une copie de test doit être faite et hachée au même instant ; `B0` compare la copie au vrai fichier avant et après la copie.
3. Dossier vide `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\REPO\3-libre` (créé le 2026-10-10 10:46, hors de `VERROU\`) : vraisemblablement un `mkdir 3-libre` fait au mauvais endroit ; sans effet sur les scripts (hors racine), non touché.
4. `git status` montre aussi `M Tools/EtatDir.ps1` et `?? Tools/GitEtat.ps1` (OUTC-T3) : pas de moi, non touchés.
5. `UeState.ps1` / `FileCheck.ps1` : `FileCheck.ps1` accepte plusieurs fichiers par `pwsh -Command "& 'Tools\FileCheck.ps1' a, b"` mais pas par `pwsh -File … a b` (« paramètre positionnel », piège connu de `lp-build` § 8) ; la commande de la fiche (`-File … <copie>`, un seul fichier) fonctionne.
6. Fixes de mise au point faits sur mes propres essais (pas sur les scripts livrés) : `Measure-Object -Maximum` rend un `double` (format `D3` invalide), citation `''` dans un `pwsh -Command` sous Git Bash, comparaison du vrai `NUMEROS.md` à un MD5 pris trop tôt.