LifePlay-Revival/Docs/Migration/etat/EVAL2/AMEL1/AMEL1-V1b-VAL.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

91 lines
12 KiB
Markdown

Fiche AMEL1-V1b — Niveau N1 — Modèle prévu sonnet | utilisé claude-sonnet-5-5 — Agent lp-validator — Skills sk-protocol, sk-recount, debug-verification, lp-validate
# AMEL1-V1b-VAL : validation de `Tools\Indicateurs.py` (fiche AMEL1-M1) contre le plan `AMEL1-INDICATEURS.md` (2026-10-14)
Verdict : **PASS avec une réserve** (R1, définition de I3, § 5). Rien n'est corrigé.
## 1. Fiches amont relues
- `AMEL1-M1-IMPL.md` (livrable de la fiche M1, lu en entier : § 1 à 6 et constats C1 à C6).
- `AMEL1-MESURE-P3.md` (sortie de M1, comparée au rejeu ; 17 743 o).
- `AMEL1-INDICATEURS.md` (plan : § 1, § 2, § 2.1 et définitions retenues).
- `Tools\Indicateurs.py` (1 715 lignes, lu en entier ; MD5 `f67033231719195d4d0facf979c2c794`, identique à celui de l'IMPL avant et après mes essais).
- Données de recompte : `etat\EVAL2\data\*.csv`, `EVAL2-T1b-INV.md` l. 47, batterie `D:\Game\LifePlay_Backup_5.5\P7-H2\`.
## 2. Points à confirmer de l'IMPL (§ 5 de M1)
| Point | Objet | Résultat |
|---|---|---|
| P1 | I5b, seuil d'activité 25 % | PASS-STATIC : le code (`i_I5b`, l. 1252-1276) applique « intervalle retenu si heures actives / durée ≥ 0,25 », lecture cohérente avec le § 2.1 ; valeur 29,3 h rejouée à l'identique (V1) mais non recalculée par une autre méthode (hors tirage). Le choix du seuil reste une décision, reporté à l'orchestrateur |
| P2 | I6, « COMMIT refus » en début d'opération | PASS-STATIC : `re.match("(?i)COMMIT refus", r[4])` (l. 851) = définition du § 2.1 ; 6 / 49 rejoué ; non recompté (hors tirage) |
| P3 | I8b, filtre des retouches en bloc et 4 liens | reporté : hors tirage, `EVAL2-T5-INV.md` l. 114-118 non relu ; le filtre est bien celui du § 2.1 (l. 1066, `bloc` ≥ 10 fichiers à la seconde) |
| P4 | I8a, critère strict ou large | reporté : décision de libellé de la règle R8 (§ 2.1 retient le strict, 1 / 34) |
| P5 | I10b, cas distincts = lots | PASS : recompté (V2) 7 relevés, 3 clés (STE, CAM, STG) |
| P6 | I12, I13, I14 écarts à l'ancien « Avant » | PASS : les trois valeurs (5 / 25, 2 / 7, 2 / 32) sont exactement celles que le § 2.1 retient ; I13 : dénominateur 7 recompté (`subagents.csv`, 7 `lp-inventory`) |
| P7 | I2b, jeu réuni ou `cas.jsonl` seul | PASS : recompté 154 / 174 (V2) ; le § 2.1 retient le jeu réuni (88,5 %) |
| P8 | fuseau UTC+2, option `--decalage-utc` | reporté : option présente (l. 1671), non exercée (aucune fenêtre après le 2026-10-25) |
| P9 | granularité du jour (I6, I10b, I11a) | PASS : constaté en V3 (I6 = 150,0 pour 2 commits de la fenêtre, 3 refus datés du jour) |
## 3. Critères rejoués
Copie `D:\Game\LifePlay-master 5.8`, branche `ue5.8`, Python 3.14.4.
### V1 rejeu P3 : PASS
Commande : `python -I -X utf8 Tools/Indicateurs.py --debut "2026-10-11 05:30:00" --fin "2026-10-14 18:25:41" --coupure "2026-10-13 12:07:16" --sortie Docs/Migration/etat/EVAL2/AMEL1/V1b/rejeu.md` → `CODE=0`, 26 s, 17 737 o.
`diff AMEL1-MESURE-P3.md V1b/rejeu.md` : code 1, **3 hunks, tous en en-tête** (ligne Commande avec le nom de sortie, ligne Sessions exclues avec l'heure et la durée, ligne Relevés avec les durées). Les 27 lignes d'indicateurs, les notes, le tableau « attendu / obtenu » et la section Etat sont **identiques octet pour octet** (0 écart sur les comptes, donc dans le ±1 admis ; y compris `I11a-fichier` 87 / 463 et BOSS-JOURNAL). Tableau de contrôle : 50 PASS, 3 FAIL (I12, I13, I14) comme dans l'IMPL ; ces 3 écarts à l'ancienne lecture manuelle sont ceux que le § 2.1 du plan a ensuite retenus.
### V2 formules, 8 indicateurs tirés (graine 20261014)
Tirage : `random.seed(20261014); random.sample(<I1a…I14 puis G-a…G-d, 27 identifiants dans l'ordre du plan>, 8)` → **G-a, I10b, I3, I13, I2b, I9, I11a, I10a** (script `scratchpad\tirage.py`).
| Ind. | Formule du code | Valeur rejeu | Recompte par autre méthode | Verdict |
|---|---|---|---|---|
| G-a (`i_Ga`, l. 1460) | (jetons principales + sous-agents) / (CHG + ERR de la fenêtre) | 2970,1 M / 76 = 39,1 M | `sessions.csv` niveau `session` 2 407,5 M + `subagents.csv` 562,4 M = 2 969,9 M (écart 0,2 M) ; `chg.csv` 26 + `err.csv` 50 = 76 | PASS |
| I10b (`i_I10b`, l. 1376) | relevés `retenu=oui`, `type_retenu=instantane_manquant`, cas = clé `(ecart X)` sinon lot | 3 cas, 7 relevés | lecture directe de `ecarts.csv` (filtre sur la fenêtre) : 7 lignes ; clés STE (4 dont BOSS/JOURNAUX1), CAM, STG = 3 | PASS (proxy « un cas = un lot », § 2.1) |
| I3 (`i_I3`, l. 1207) | KO avec découvreur agent ou script / KO avec découvreur | 12,5 % = 6 / 48 | `commun.csv` : 6 agent, 3 mixte, 39 utilisateur = 48 ; 13 builds de la fenêtre. Voir réserve R1 | PASS avec réserve |
| I13 (`i_I13`, l. 1435) | passages `lp-inventory` avec refus ET (dernier résultat refus, ou compte rendu cite un refus, ou fin sans compte rendu, ou reprise) | 2 / 7 | dénominateur : 7 `lp-inventory` dans `subagents.csv`. Numérateur : proxy, non recompté ligne à ligne (le § 2.1 retient 2 / 7) | PASS (dénominateur), numérateur incertain |
| I2b (`i_I2b`, l. 1184) | cas dont l'attendu est « refus » refusés (code 2) / cas dont l'attendu est « refus », 3 jeux réunis | 88,5 % = 154 / 174 | script indépendant `scratchpad\recompte2.py` : 3 jeux de 69, 138, 56 cas, 174 adverses, 154 refusés ; non refusés : A6, A7, A12, V03, V29, V49, H01 à H12, G01, G02 (20, liste identique à C5 de l'IMPL) ; MD5 des jeux `7851f65a`, `a670c5e3`, `6343f981` | PASS |
| I9 (`i_I9`, l. 1354) | `lp-cart` hors budget (tours ou pic) / passages `lp-cart` | 79 % = 11 / 14 | `subagents.csv` : 14 `lp-cart`, 11 `hors_budget` ; `EVAL2-T1b-INV.md` l. 47 : « 14 … 79 % » | PASS |
| I11a (`i_I11a`, l. 1393) | lignes du BOSS-JOURNAL de la fenêtre avec `HH:MM` / lignes de la fenêtre | 19,0 % = 51 / 268 | Grep (compte) `^\| 2026-10-1[1-4]` : 268 ; `^\| 2026-10-1[1-4][ T]\d{1,2}:\d{2}` : 51 | PASS |
| I10a (`i_I10a`, l. 1364) | CopieEtat + GitEtat / (eux + git status + empreintes) | 4,0 % = 66 / 1 655 | `commandes.csv` : CopieEtat 43 + GitEtat 23 = 66 ; git status 662 ; familles `a.*` 168 + 16 + 4 + 730 + 9 = 927 (union 927) ; 66 + 662 + 927 = 1 655 | PASS |
Aucune des 8 formules ne s'écarte du § 2 ni du § 2.1, sauf la nuance R1 de I3. Les relevés de `commun.csv` sont de la saisie manuelle (E4 de l'IMPL) : le recompte confirme le calcul, pas la saisie.
### V3 chemin d'échec : PASS
Commande : `python -I -X utf8 Tools/Indicateurs.py --debut "2026-10-14 18:30:00" --fin "2026-10-14 21:00:00" --sortie Docs/Migration/etat/EVAL2/AMEL1/V1b/echec.md` → `CODE=1`, 14 lignes `NON MESURABLE : <raison>` (I2a, I3, I4a, I4b, I5a, I5b, I8a, I8b, I9, I11b, I13, I14, G-c, G-d), chacune avec sa raison (par exemple I3 : « aucun essai commun de la fenetre dans builds.csv … fournir --builds-csv et --commun-csv »). 13 autres indicateurs sont calculés sur la petite activité de la fenêtre (35 tours, 7 appels shell de sous-agents) : la fenêtre n'est donc pas « sans aucune donnée », mais le critère (code 1, lignes NON MESURABLE motivées) est rempli. Observations : I6 = 150,0 pour 100 commits (artefact de P9) et I2b = 88,5 % (indépendant de la fenêtre).
### V4 innocuité : PASS
- Lecture du code en entier. Écriture : seul `ecrire_sortie` (l. 1651-1653 : `os.makedirs` du dossier de `--sortie`, `open(cfg.sortie, "w")`). Grep `ls-remote|urllib|socket|requests|http|shutil|os.remove|rename|unlink` : seule occurrence = le commentaire l. 23.
- Sous-processus (`subprocess.run`, l. 115 et 814) : `git log`, `git log --all`, `git log -p`, `git rev-parse --short HEAD` (lecture seule, `GIT_TERMINAL_PROMPT=0`, délai 600 s) et le crochet lancé par `sys.executable -I` sur une charge JSON simulée, depuis le dossier temporaire ; aucune commande de la batterie n'est exécutée.
- Crochet `%USERPROFILE%\.claude\hooks\ecriture-gardien.py` : MD5 `f00d973927cd292723a82be859d5c5bd` avant (début) et après (fin, après 2 rejeux du script et mon recompte de 174 charges simulées) = inchangé.
- Fichiers apparus pendant la validation : uniquement `etat\EVAL2\AMEL1\V1b\rejeu.md` et `echec.md` (`git status --short` ne montre de neuf que `V1b/` pour ce dossier ; `Tools/Indicateurs.py` était déjà non suivi).
### V5 fichier : PASS
- LF : `tr -cd '\r' < … | wc -c` = 0 pour `Indicateurs.py`, `AMEL1-M1-IMPL.md`, `AMEL1-MESURE-P3.md`, `rejeu.md`, `echec.md`.
- Bibliothèque standard : imports l. 33-46 + `shlex` (l. 225) = argparse, collections, csv, datetime, glob, hashlib, json, os, re, statistics, subprocess, sys, tempfile, time, shlex ; rien d'autre.
- `python -I -X utf8 Tools/Indicateurs.py --help` : code 0 (`HELP=0`).
- `pwsh -NoProfile -File Tools/PubCheck.ps1 -Fichiers Tools/Indicateurs.py Docs/Migration/etat/EVAL2/AMEL1/AMEL1-M1-IMPL.md Docs/Migration/etat/EVAL2/AMEL1/AMEL1-MESURE-P3.md` → `PubCheck : 0 constat(s)`, code 0. (Un second appel sur les sorties `V1b/*.md` en chemin relatif a répondu `fichier introuvable`, code 2 : erreur de chemin de ma part, non rejoué, hors critère.)
## 4. Diff lu en entier
Fichier neuf non suivi : `Tools/Indicateurs.py` lu intégralement (1 715 lignes, 3 pages de lecture) ; `AMEL1-M1-IMPL.md` lu en entier. Pas de tag `AMEL1-M1-avant` pertinent (fichiers neufs, `Existed=False` d'après l'IMPL § 3). Non rejoué : `Snapshot.ps1`/`FileCheck.ps1` (sans objet, fichier neuf), compilation, `LPTestStringCompat` (sans objet, script Python).
## 5. Verdict : PASS (avec réserve R1)
| Critère | Verdict |
|---|---|
| V1 rejeu | PASS |
| V2 formules (8 / 8) | PASS (R1 sur I3) |
| V3 chemin d'échec | PASS |
| V4 innocuité | PASS |
| V5 fichier | PASS |
Témoin en jeu : sans objet (outil de mesure, aucun comportement du jeu ne change).
Écarts et réserves :
1. **R1, I3, dénominateur** : `i_I3` (l. 1209) retient `type == "cas"` avec découvreur quel que soit le verdict, donc 8 lignes `OK_PARTIEL` (1 agent, 2 mixte, 5 utilisateur) entrent dans les 48 « KO ». La formule du plan dit « cas KO, KO partiels et défauts hors fiche KO ». Lecture stricte (`KO`, `KO_PARTIEL` et `hors_fiche` `KO`) : 5 / 40 = 12,5 %, soit la même valeur que 6 / 48. Le plan donne lui-même « 6 / 48 », donc le code reproduit le plan, mais la définition de la P4 doit trancher (inclure ou non `OK_PARTIEL`), sinon la comparaison avant / après peut changer de sens sans que l'outil le dise.
2. **R2, I10a** (observation) : le dénominateur additionne les familles `a.*` (`somme_emp`, l. 1367) au lieu de prendre l'union des appels ; égal en P3 (927 = 927), peut compter deux fois un appel qui porte deux empreintes en P4.
3. **R3, I13 et I5b** : valeurs rejouées mais numérateur de I13 (proxy) et valeur de I5b non recomptés par une autre méthode (hors tirage).
4. Données saisies (I3, G-c, G-d, I8b, I10b) : le calcul est confirmé, la saisie manuelle des CSV n'est pas vérifiée.
## 6. Points à confirmer par l'utilisateur
- [ ] I3 : compter ou non les cas `OK_PARTIEL` avec découvreur dans les KO (R1) ; à fixer avant la P4.
- [ ] I8a : libellé exact de la règle R8 (critère strict ou large) avant la mesure P4.
- [ ] I5b : seuil d'activité de 25 % (P1).
- [ ] Après le 2026-10-25 : passer `--decalage-utc 1` si la fenêtre P4 franchit l'heure d'hiver (P8).
Tours : 14 / 40
## Constats
Fichiers écrits : `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\EVAL2\AMEL1\AMEL1-V1b-VAL.md`, `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\EVAL2\AMEL1\V1b\rejeu.md`, `D:\Game\LifePlay-master 5.8\Docs\Migration\etat\EVAL2\AMEL1\V1b\echec.md`. Scripts de recompte (hors dépôt) : `%LOCALAPPDATA%\Temp\claude\D--Game-LifePlay-master-5-8\be193763-a670-4b37-9245-ae89a7580435\scratchpad\{tirage,recompte,recompte2,recompte3}.py`.
Fichiers à commiter : A `Docs/Migration/etat/EVAL2/AMEL1/AMEL1-V1b-VAL.md`, A `Docs/Migration/etat/EVAL2/AMEL1/V1b/rejeu.md`, A `Docs/Migration/etat/EVAL2/AMEL1/V1b/echec.md` (dépôt jeu, branche `ue5.8`) ; aucun autre fichier modifié.