LifePlay-Revival/Docs/Migration/22_Eval_Agents_Sandbox.md

218 lines
18 KiB
Markdown
Raw Permalink Normal View History

# 22. Évaluation du mode multi-agents + multi-modèles (migration sandbox → addon, S0–S8)
- **Date :** 2026-10-06 | **Fiche :** S8-T1 | **Rôle :** A-DOC+Orch | **Entrée journal :** CHG-220
- **Modèle prévu :** `claude-opus-5-5-medium` (M4) | **Modèle utilisé :** Claude Opus 5.5 (déclaré par l'environnement)
- **Sources :** `etat/sandbox/S0/` à `S7/` (29 rapports `*-CART`, `*-SPEC`, `*-IMPL*`, `*-INT*`, `*-VAL`), `21_Sandbox_Addon.md`,
journal `CHG-212` à `CHG-219`, état git des deux dépôts au 2026-10-06 21:00.
- **Validation de clôture :** [`etat/sandbox/S8/S8-VAL.md`](etat/sandbox/S8/S8-VAL.md) (smoke Pair par le `.bat`, **PASS**).
**Biais à garder en tête :** ce bilan est écrit par le rôle orchestrateur, qui juge en partie sa propre organisation. Les
faits (verdicts, horodatages, état git) sont vérifiables dans les fiches citées ; les appréciations (sur/sous-classement,
coût) sont des jugements.
---
## 1. Résumé exécutif
**Fait.** Le code sandbox (Pair, Interaction, Mesure, ~7,5 k LOC) est sorti du module jeu vers le plugin `LPSandbox` du
dépôt séparé `LifePlay-Sandbox`, chargé par le jeu via `AdditionalPluginDirectories` (clone sibling, pin manuel). La
chaîne de mesure est un module à part (`LPAnimMeasure`), la géométrie du couple n'existe plus qu'en une copie
(`LPCoupleSim`, −336 lignes dupliquées), le plugin ne connaît pas le jeu à la compilation (0 include / `LIFEPLAY_API`) et
`LPSandbox` est exclu du Shipping. Huit validations PASS, aucune régression observée : la boîte du couple `AgMakeout` est
identique au millième de cm entre S5, S7 et S8. Aucun retour arrière n'a été nécessaire. Le tout a été fait en une
journée (S1 → S7 en ~3 h d'après les horodatages des fiches, 18:18 → 20:54).
**Limites.**
- **Rien n'est commité côté jeu** : `LifePlay.uproject`, `Config/LPSandbox.ini`, `21`, `etat/sandbox/**`, et
`LPShowCoupleSubsystem.*` (non suivis). Un clone du jeu aujourd'hui ne monte pas l'addon ; le pin n'a de valeur
que sur ce poste.
- **Show en jeu jamais exécuté** : le partage `LPCoupleSim` côté jeu n'est prouvé que par compilation (PASS-STATIC,
S5) ; l'alignement du plancher −90 / −88 n'est pas décidé.
- **Shipping non compilé** (plan UBT seulement), commandlets anim (`Catalog`, `Checks`, `Twist`) toujours dans
`LifePlayEditorTools`, `BuildMod -Target sandbox` non rejoué.
- **Le build du jeu dépend du clone sibling** (`LifePlay.Build.cs` → `LPAnimMeasure`) malgré `Optional: true`.
- Preuves par journal uniquement : aucun contrôle visuel, modes Interaction et Mesure non exercés après S2.
---
## 2. Lots S0–S8
« Rollback » = retour arrière **exécuté**. Tous les lots ont un retour arrière documenté dans le journal ; celui des
lots S1, S2 et S5 côté jeu porte sur des fichiers non suivis par git, donc sans instantané : il est manuel et non testé.
| Lot | Tenu | Coupé / reporté | Rollback | Verdict VAL |
|---|---|---|---|---|
| **S0** | `.gitignore` `/Debug/`, 3 bats suivis, inventaire gelé | — | aucun | **PASS** (`S0-VAL`) |
| **S1** | `Config/LPSandbox.ini` (19 clés, 6 sections), `FLPSandboxConfig`, 0 littéral oublié | compilation et runtime (DLL plus ancienne que les sources) ; test d'override `WorldFile` laissé « manuel », jamais fait | aucun | **PASS statique** (`S1-VAL`, runtime BLOCKED) |
| **S2** | module `LPAnimMeasure` (8 fichiers, 6 exports), graphe acyclique, runtime Mesure (269 lignes `LogLPAnimMeasure`) | commandlets non relancés (repris en S6 pour `LPAnimEval` seul) ; mise à jour de `S1-CART` demandée, **jamais faite** | aucun | **PASS** (`S2-VAL`) |
| **S3** | dépôt addon, transfert, purge du jeu, `AdditionalPluginDirectories`, pin, build 91/91 | **submodule abandonné** ; addon mince avec réserve (plugin `StreetMap` absent, 2 458 erreurs BP sans effet) | **partiel** : la junction `Plugins\LPSandbox` créée en S3-T3 a été retirée en S3-T4 | **PASS** avec réserve (`S3-VAL`) |
| **S4** | `LPPairSandbox.cpp` 4 274 → 7 unités (max 837 LOC), GameMode Interaction legacy retiré (~543 LOC) | commandlet `LPPairCollisionTest` cité dans l'objet du lot : non traité ; mode Interaction non exercé | aucun | **PASS** (`S4-VAL`) |
| **S5** | `LPCoupleSim` partagé (3 niveaux d'API), 0 erreur / 0 avertissement, parité de la boîte | Show en jeu, décision du plancher, tests unitaires du niveau pur, mise sous git de `LPShowCoupleSubsystem` | aucun | **PASS** runtime Pair / **PASS-STATIC** Show (`S5-VAL`) |
| **S6** | doc `20` / `09` alignées, `LPAnimEval` court (code 0, 1,3 s) | bat Mesure non rejoué (renvoi à S2-VAL) | aucun | **PASS** (`S6-VAL`) |
| **S7** | contrat d'isolation (0 écart), `TargetConfigurationDenyList: Shipping`, `Optional` | compilation Shipping ; déplacement des commandlets ; push (fait après coup, constaté en S8) | aucun | **PASS** (`S7-VAL`) |
| **S8** | ce bilan ; smoke Pair par le `.bat` réel, parité de la boîte | `BuildMod -Target`, bout en bout Show | aucun | **PASS** (`S8-VAL`) |
---
## 3. Qualité des consignes et des handoffs
**Ce qui a marché.**
- Chaque VAL cite ses références, le pin, le journal copié et une section « Limites » ; les verdicts nuancés
(`PASS statique`, `PASS-STATIC`, `BLOCKED-RUNTIME`, « avec réserve ») ont empêché de sur-vendre un lot.
- L'enchaînement CART → IMPL-H a payé : S3-T2, S4-T2 et S5-T2 ont compilé du premier coup, sans include à corriger
(hors un défaut IWYU révélé par l'unity en S2).
- Les écarts à la fiche sont déclarés au lieu d'être cachés : S4-T2 (7 unités au lieu de 5, justifié par la taille),
S5-T2 (5 écarts de comportement listés exhaustivement), S7-T2 (options rejetées avec motif).
**Ambiguïtés de consigne observées.**
| Où | Ambiguïté | Effet |
|---|---|---|
| S1-T2 / S1-T4 | IMPL-L sans consigne de compiler, VAL sans droit de compiler | personne n'a compilé S1 ; le runtime n'a été prouvé qu'indirectement par S2 |
| S3-T3 / S3-T4 | plan « submodule en T4 » alors que la structure de l'addon (plugin imbriqué) le rendait impossible | junction temporaire créée puis retirée, décision d'architecture prise en INT |
| S3-T1, S7-T2 | « push non autorisé » sans dire qui pousse ni quand | pin pointant un commit local entre S7-T2 et la fin de S7 |
| S4 | objet du lot dans `21` (commandlet `LPPairCollisionTest`) ≠ fiches exécutées | item tombé sans trace de décision |
| S7 / S8 | libellés de `21` (S7 « commandlets », S8 « épuration, `BuildMod -Target` ») ≠ fiches reçues | S7-VAL doit signaler un « ancien libellé non traité » ; S8 ici = bilan, pas épuration |
| `21` § Lots | ligne S1 toujours « placeholder ci-dessus » | doc de référence partiellement périmée |
**Reprises.** S1 runtime → couvert par S2 ; commandlets S2 → `LPAnimEval` en S6 (les autres jamais) ; junction S3-T3 →
retirée S3-T4 ; bat équivalent S7 → bat réel S8 ; push S7 → fait (constaté S8). **Orphelins** (demandés, jamais
repris) : mise à jour `S1-CART`, test d'override `WorldFile`, Show en jeu, commit côté jeu.
**Forme.** Les fiches S3-INT et S7 sont écrites sans accents et sans en-tête « Modèle », les autres avec : le
gabarit de fiche n'était pas imposé.
---
## 4. Adéquation modèle ↔ complexité
Paliers d'après les fiches : M0 = `composer-2.5-fast`, M2 = `claude-sonnet-5-5-high`, M3 = `claude-opus-5-thinking-high`,
M4 = `claude-opus-5-5-medium` ; `gemini-3.8-flash-high` n'a pas de palier noté (M1 supposé). « Réel » = champ « Modèle
utilisé » de la fiche ; sinon « non tracé dans VAL », et l'évaluation porte sur le prévu. **12 fiches sur 28 tracent
le modèle réel (11 sur 27 avant S8).**
| Fiche | Rôle | Modèle prévu | Réel | Résultat | Classement |
|---|---|---|---|---|---|
| S0-T1 | CART | gemini-3.8-flash-high | idem | inventaire exact | adéquat |
| S0-T2 | IMPL (`.gitignore`) | non tracé | non tracé dans VAL | 1 ligne, PASS | — |
| S0-T3 | VAL | composer-2.5-fast (M0) | idem | PASS, preuve `check-ignore` | adéquat |
| S1-T1 | ARCH (SPEC) | non tracé | non tracé dans VAL | contrat solide, réutilisé jusqu'en S7 | — |
| S1-T2 | IMPL-L | non tracé | non tracé dans VAL | correct mais **non compilé** | — (défaut de consigne, pas de modèle) |
| S1-T3 | CART (audit grep) | gemini-3.8-flash-high | idem | 0 oubli, confirmé par VAL | adéquat |
| S1-T4 | VAL | sonnet (M2) | idem | bon diagnostic (DLL > sources) mais checklist statique | **légèrement sur-classé** (M0 a fait des VAL plus lourdes en S4/S6) |
| S2-T1 | CART | sonnet (M2) | non tracé dans VAL | cartographie fiable | adéquat |
| S2-T2 | IMPL-H | opus thinking (M3) | non tracé dans VAL | compilé, 1 fix IWYU | **sur-classé** (déplacement + exports, M2 suffisait) |
| S2-T4 | VAL | sonnet (M2) | idem | PASS runtime Mesure | adéquat |
| S3-T1 | INT (scaffold) | sonnet (M2) | non tracé dans VAL | scaffold correct, push gelé | adéquat |
| S3-T2 | IMPL-H | opus thinking (M3) | non tracé dans VAL | transfert inter-dépôts compilé du premier coup | adéquat |
| S3-T3 | IMPL-L (purge jeu) | composer (M0) | composer (champ unique) | purge correcte, **sans build**, junction contraire à la décision finale | **sous-classé** (opération destructive inter-dépôts) |
| S3-T4 | INT | non tracé | non tracé dans VAL | abandon du submodule, build 91/91, premier push | — |
| S3-T5 | VAL | sonnet (M2) | idem | deux runtimes, cause `StreetMap` identifiée | adéquat |
| S4-T1 | CART | non tracé | non tracé dans VAL | découpage exploitable | — |
| S4-T2 | IMPL-H | opus thinking (M3) | non tracé dans VAL | 4 274 LOC découpés, 0 erreur | adéquat (risque élevé, aucune régression) |
| S4-T3 | IMPL (retrait GM) | non tracé | non tracé dans VAL | suppression propre | — |
| S4-T4a | VAL | composer (M0) | idem | build + runtime, PASS | adéquat |
| S5-T1 | CART | sonnet (M2) | non tracé dans VAL | 28 Ko d'écarts précis, base de S5-T2 | adéquat |
| S5-T2 | IMPL-H | opus thinking (M3) | idem | refonte de comportement, 0 avertissement, écarts listés | adéquat |
| S5-T3 | VAL | sonnet (M2) | idem | parité argumentée, PASS-STATIC honnête | adéquat |
| S6-T1..T3 | VAL (+DOC) | composer (M0) | idem | PASS, commandlet court | adéquat |
| S7-T1 | ARCH (SPEC) | non tracé | non tracé dans VAL | checklist C1–C5 réutilisable | — |
| S7-T2 | IMPL-L | non tracé | non tracé dans VAL | uplugin / uproject corrects | — |
| S7-T3 | CART | non tracé | non tracé dans VAL | 0 écart | — |
| S7-T4 | VAL+DOC | non tracé | non tracé dans VAL | PASS, limites claires | — |
| S8-T1/T2 | DOC+Orch, VAL | opus 5.5 medium (M4) | Claude Opus 5.5 (effort non vérifiable) | ce document, smoke PASS | adéquat pour la synthèse ; M0 suffirait pour le smoke seul |
**Lecture.** Aucun échec imputable au modèle. Les deux défauts notables viennent de la **consigne** (S1 sans build) et
d'un **palier trop bas pour une opération destructive** (S3-T3). Le sur-classement (S2-T2, S1-T4) n'a rien cassé, il
coûte seulement. M0 s'est montré suffisant pour toutes les VAL à checklist + smoke.
---
## 5. Erreurs d'affectation de rôle
1. **VAL qui écrit la doc qu'elle valide** : S2-T4b (« A-VAL puis prep DOC »), S6 (VAL a fait la mise à jour de `20` /
`09` puis l'a validée), S7-T4 (« VAL+DOC », coche elle-même `21` § Acceptation). Pas d'erreur constatée, mais la
séparation des rôles perd son intérêt.
2. **Décision d'architecture prise par INT** : l'abandon du submodule (S3-T4) relevait d'A-ARCH ; il a été pris en
intégration, sans SPEC préalable, et documenté a posteriori dans `21`.
3. **Compilation sans propriétaire en S1** : ni IMPL-L ni VAL n'avaient le droit de compiler ; le trou a été comblé par
chance au lot suivant.
4. **Purge destructive confiée à IMPL-L / M0 (S3-T3)** : suppression de fichiers du jeu et modification du
`.uproject`, sans build dans la fiche.
5. **Orchestrateur évaluateur (S8-T1)** : le rôle qui a découpé les lots en fait le bilan ; voir le biais signalé en tête.
---
## 6. Friction git
- **Submodule abandonné → `AdditionalPluginDirectories`.** Le plan initial (S3-T3 : « jonctions temporaires, avant
submodule T4 ») supposait un submodule. L'addon étant un `uproject` qui contient `Plugins/LPSandbox/`, un submodule
monté sur `Plugins/LPSandbox` du jeu aurait donné `Plugins/LPSandbox/Plugins/LPSandbox/` (non scanné), et un
submodule `External/` aurait doublé le clone sibling. S3-T4 a retiré la junction et retenu deux clones voisins +
`AdditionalPluginDirectories` + pin consigné à la main (`S3-INT.md`, README). Coût : une junction créée puis
défaite, et un pin que rien n'automatise (4 bumps à la main : `4de1f0b`, `f810264`, `c1fdd29`, `f09c42e`).
- **Push.** S3-T1 a créé le remote sans pousser (consigne) ; premier push en S3-T4. S7-T2 a laissé `f09c42e` local et
le pin pointait un commit absent du remote jusqu'à la fin de S7. Constat S8 : `origin/main` = `dae6206` (contient
`f09c42e`), **l'addon est à jour sur GitHub**. Côté jeu, en revanche, **aucun commit depuis le début du lot** : le
dernier commit touchant `LifePlay.uproject` est antérieur (`b11f7e8`) ; `21`, `etat/sandbox/**`,
`Config/LPSandbox.ini` sont non suivis, `LifePlay.uproject` et les deux `Build.cs` modifiés non commités. Le pin
documenté n'est donc consommable par personne d'autre.
- **Identité git.** Les deux premiers commits de l'addon (`4938abb` S3-T1, `d18243e` S3-T2) portent
`LifePlay <lifeplay@localhost>` : identité non configurée dans le nouveau dépôt. Les suivants portent
`edujiro5972 <edujiro5972@users.noreply.github.com>`, alors que le dépôt jeu utilise
`336072401+edujiro5972@users.noreply.github.com`. Trois identités pour un seul auteur ; l'historique publié n'a pas
été réécrit (il faudrait un push forcé).
---
## 7. Coût / bénéfice vs mono-agent mono-modèle
**Coût mesurable.**
- 27 fiches (S0–S7) et 29 rapports, ~200 Ko de Markdown sous `etat/sandbox/` (S5 seul : 52 Ko) pour un changement net de
quelques milliers de lignes déplacées et −336 lignes dupliquées.
- Chaque agent relit `21` et les fiches amont : le contexte est rechargé ~28 fois.
- Trous de transmission que la continuité d'un seul agent aurait évités : S1 non compilé, junction S3 défaite,
`S1-CART` jamais mis à jour, commit jeu jamais fait.
- Traçabilité incomplète : 11 fiches sur 27 (S0–S7) indiquent le modèle réel.
**Bénéfice mesurable.**
- 0 build cassé à l'étape IMPL-H, 0 retour arrière, 0 régression (parité de la boîte S5 = S7 = S8).
- Des VAL indépendantes qui ont refusé de sur-vendre : `BLOCKED-RUNTIME` en S1, `PASS-STATIC` en S5, réserve
`StreetMap` en S3. Un agent unique valide plus volontiers son propre travail.
- Les paliers bas (M0, flash) ont porté 5 fiches de VAL / CART sans défaut (S0-T1, S0-T3, S1-T3, S4-T4a, S6) ; un
mono-modèle haut de gamme aurait payé ces fiches au prix fort.
**Verdict.** Pour une migration à risque (déplacement inter-dépôts, refonte de géométrie partagée), le surcoût
documentaire est justifié par l'absence de régression et la qualité des preuves. Pour des lots simples (S0, S6, S7-T2)
le découpage en 3–4 rôles est du surcoût pur : un seul agent M0/M2 avec une VAL séparée suffisait.
---
## 8. Décision
**GO conditionnel** pour réutiliser le mode multi-agents + multi-modèles sur les prochaines migrations de même nature
(extraction de code, refonte partagée jeu ↔ addon). Les trois conditions sont les recommandations ci-dessous ; sans
elles, les mêmes trous (build sans propriétaire, git non clos, traçabilité partielle) se reproduiront.
**NO-GO** pour les lots simples (≤ 1 fichier de config / doc, pas de C++) : un agent unique + une VAL M0.
---
## 9. Recommandations (3)
1. **Politique modèles, tracée et vérifiée.** M0 (`composer-2.5-fast`) par défaut pour les VAL à checklist + smoke et
les IMPL-L mécaniques non destructives ; `gemini-3.8-flash-high` pour les CART de type grep ; M2
(`claude-sonnet-5-5-high`) pour les CART analytiques, les VAL qui doivent juger une parité ou un PASS-STATIC, **et
toute opération destructive ou inter-dépôts** (suppression de sources, `.uproject`) ; M3
(`claude-opus-5-thinking-high`) réservé aux IMPL-H qui changent un comportement (type S5-T2), pas aux déplacements
(type S2-T2 → M2) ; M4 pour la synthèse transverse. Chaque fiche porte « Modèle prévu | utilisé » ; une VAL sans ce
champ dans les fiches amont est en `FAIL-TRACE`.
2. **Clôture git par lot, avec un propriétaire.** Toute fiche IMPL finit par un build vert (la compilation appartient à
IMPL, pas à VAL). Le lot ne passe au suivant qu'après un « gate » A-INT : commit + push de l'addon, bump du pin,
**commit du jeu** (fichiers non suivis inclus), identité git vérifiée (`git config user.email` identique dans les
deux dépôts). Prochaine action concrète : commiter côté jeu `LifePlay.uproject`, `Config/LPSandbox.ini`, les
`Build.cs`, `LPShowCoupleSubsystem.*`, `21`, `22` et `etat/sandbox/`.
3. **Séparer VAL et DOC, et tenir un registre des reports.** La VAL est en lecture seule sur les docs d'acceptation ;
un rôle DOC distinct coche `21`. Les décisions d'architecture passent par une SPEC avant l'INT. Chaque « reste à
faire » d'une fiche entre dans une liste unique de `21` avec un lot propriétaire, pour qu'aucun report ne reste
orphelin (aujourd'hui : `S1-CART`, override `WorldFile`, Show en jeu, plancher, commandlets, Shipping compilé).