LifePlay-Revival/Docs/Migration/22_Eval_Agents_Sandbox.md
edujiro5972 04b053554f Sandbox addon : brancher le jeu sur LifePlay-Sandbox (plugin LPSandbox).
Charge le plugin via AdditionalPluginDirectories, conserve ShowCouple et les commandlets anim côté jeu, et documente les lots S0–S8 (CHG-212 à CHG-220).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 21:10:53 +02:00

217 lines
18 KiB
Markdown
Raw Permalink 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.

# 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é).