LifePlay-Revival/Docs/Migration/etat/CAM/CAM-B2b-IMPL-F5.md

215 lines
16 KiB
Markdown
Raw Normal View History

Fiche CAM-B2b-F5 — Niveau N3 — Modèle prévu opus | utilisé claude-opus-5-5 (Opus 5.5) — Agent lp-mcp-bp — Skills sk-protocol, sk-change-safety, lp-mcp, lp-lot
# CAM-B2b-F5-IMPL : repli vers le haut (B2b-3) (2026-10-13)
Consignes : `CAM-B2b-FICHES.md` § « Rubriques communes » (l. 23-63) et § « F5 » (l. 115-125) ; SPEC `CAM-SPEC.md`
§ « CAM-B2b », ligne B2b-3 (l. 377). UE-GO / BUILD-GO de Big Boss du 2026-10-13 (cité par l'orchestrateur). Éditeur
headless PID 10708, port 8000, connexion `unreal-mcp` partagée (MCPA-T1) ; Room chargé avec F1 à F4 en mémoire. Un seul
`call_tool` par message ; 54 appels MCP au total (15 `create_node`, 29 `connect_pins`, 6 `set_pin_value`,
3 `get_node_infos`, 1 `compile_blueprint`). Aucun `break_pins`, `delete_node`, `save_assets`, `write_graph_dsl` ni
`ProgrammaticToolset`.
## 1. Fichiers modifiés
- `Content/BPs/Room.uasset` : modifié **en mémoire de l'éditeur seulement**, non enregistré (pas de `save_assets`
avant F7). Preuve : MD5 disque après F5 = MD5 de l'instantané (§ 3).
- Graphe `/Game/BPs/Room.Room:EventGraph`, fin de `ComputeC2Target` (CE47), après `VariableSet_61` / `_62`
(x 36900) ; nœuds neufs en x 36700-40300, y 1500-2350.
### 1.1 Lecture avant écriture (`get_node_infos` groupé, 7 nœuds existants)
Conforme à la fiche : `VariableSet_61` (`|SetC2Target`, execute ← `IfThenElse_90`.0, C2Target ← `CallFunction_496`)
et `VariableSet_62` (`|SetC2Target`, execute ← `IfThenElse_90`.1, C2Target ← `CallFunction_495`) : `then` 0 **libre**
pour les deux ; `CallFunction_455` (`Transformation|GetSocketLocation`, self ← `VariableGet_264`, `head`) sortie 0 →
457, 459, 464, 473, 499 ; `CallFunction_497` (`Math|Vecteur|RotateVectorAroundAxis`, InVect ← PO17, AngleDeg ← 288,
Axis `0.0,0.0,1.0`) sortie 0 → PO3.A ; `MakeArray_5` ([0] ← 261, [1] ← 268) → 459.6, 499.6 ; `VariableGet_286`
(`|GetC2BoxMin`) → 495, 496, 502 ; `VariableGet_287` (`|GetC2BoxMax`) → 495, 496, 502.
### 1.2 Nœuds créés (préfixe `refPath` : `/Game/BPs/Room.Room:EventGraph.`)
| Rôle | `refPath` (suffixe) | `type_id` demandé → relu | Broches relues | Position |
|---|---|---|---|---|
| **Branche** du repli | `K2Node_IfThenElse_95` | `Utilitaires\|ContrôleDeFlux\|Branche` → idem | execute 0, Condition 1 ; then 0, else 1 | 37400, 1550 |
| Obtenir C2Target | `K2Node_VariableGet_291` | `Variables\|Pardéfaut\|ObtenirC2Target` → `\|GetC2Target` | C2Target out 0 (Vector) | 36700, 1900 |
| Distance(C2Target, tête) | `K2Node_CallFunction_503` | `Math\|Vecteur\|Distance(Vector)` → idem | V1 0, V2 1 ; out 0 (`Float (double-précision)`) | 36950, 1900 |
| Distance < 80 | `K2Node_PromotableOperator_22` | `Utilitaires\|Opérateurs\|Inférieurà(<)` → `Math\|Flottant\|float<float` (après liaison A) | A 0, B 1 (double) ; out 0 (Booléen) | 37150, 1900 |
| Bdir × 60 | `K2Node_PromotableOperator_23` | `Utilitaires\|Opérateurs\|Multiplier` → `Math\|Vecteur\|vector*vector` | A 0, B 1 ; out 0 | 37650, 2350 |
| tête + (0,0,100) | `K2Node_PromotableOperator_24` | `Utilitaires\|Opérateurs\|Ajouter` → `Math\|Vecteur\|vector+vector` | A 0, B 1 ; out 0 | 37650, 2150 |
| (tête + 100 Z) + Bdir × 60 | `K2Node_PromotableOperator_25` | `Utilitaires\|Opérateurs\|Ajouter` → `Math\|Vecteur\|vector+vector` | A 0, B 1 ; out 0 | 37900, 2250 |
| **`Desired2`** = borne | `K2Node_CallFunction_504` | `Math\|Vecteur\|VectorBoundedtoBox` → `Math\|Vecteur\|Vector_BoundedToBox` | InVect 0, InBoxMin 1, InBoxMax 2 ; out 0 | 38150, 2250 |
| **Trace** du repli | `K2Node_CallFunction_505` | `Collision\|SphereTraceByChannel` → idem | execute 0, Start 1, End 2, Radius 3, TraceChannel 4, bTraceComplex 5, ActorsToIgnore 6, DrawDebugType 7, bIgnoreSelf 8, TraceColor 9, TraceHitColor 10, DrawTime 11 ; then 0, OutHit 1, ReturnValue 2 | 38450, 1500 |
| `BreakHitResult` | `K2Node_CallFunction_506` | `Collision\|BreakHitResult` → idem | Hit 0 ; Location out 4, Normal out 6 (18 sorties) | 38900, 2000 |
| Normal × 20 | `K2Node_PromotableOperator_26` | `Utilitaires\|Opérateurs\|Multiplier` → `Math\|Vecteur\|vector*vector` | A 0, B 1 ; out 0 | 39250, 2250 |
| Location + (Normal × 20) | `K2Node_PromotableOperator_27` | `Utilitaires\|Opérateurs\|Ajouter` → `Math\|Vecteur\|vector+vector` | A 0, B 1 ; out 0 | 39500, 2050 |
| `SelectVector` | `K2Node_CallFunction_507` | `Math\|Vecteur\|SelectVector` → idem | A 0, B 1, bPickA 2 ; out 0 | 39750, 1950 |
| Borne finale | `K2Node_CallFunction_508` | `Math\|Vecteur\|VectorBoundedtoBox` → `Math\|Vecteur\|Vector_BoundedToBox` | InVect 0, InBoxMin 1, InBoxMax 2 ; out 0 | 40000, 1950 |
| **Définir C2Target** (repli) | `K2Node_VariableSet_66` | `Variables\|Pardéfaut\|DéfinirC2Target` → `\|SetC2Target` | execute 0, C2Target 1 ; then 0, Output_Get 1 | 40300, 1500 |
À la création, les opérateurs portent le `type_id` trompeur déjà vu en F3 et F4 (`…|Seconds*FrameRate`,
`…|FrameNumber+Int`, et pour le comparateur `Math|Durée|Timespan<Timespan`), avec des broches `Caractère de
remplacement`. À la relecture finale, ils sont typés `Vector`, ou `Float (double-précision)` pour PO22.
Réutilisés sans copie (nœuds purs) : 455 (tête), 497 (`Bdir`), `MakeArray_5`, `VariableGet_286`, `VariableGet_287`.
### 1.3 Liens coupés
sans objet : la fiche F5 n'en prescrit aucun (61.then et 62.then étaient libres, relu au § 1.1) ; aucun `break_pins`.
### 1.4 Liens faits (`connect_pins`, 29, tous `{"returnValue":null}`)
| # | Sortie | Entrée | Point de la fiche |
|---|---|---|---|
| L1 | VariableSet_61.then 0 | IfThenElse_95.execute 0 | 1 |
| L2 | VariableSet_62.then 0 | IfThenElse_95.execute 0 | 1 |
| L3 | VariableGet_291.0 (`C2Target`) | CallFunction_503.V1 0 | 2 |
| L4 | CallFunction_455.0 (tête) | CallFunction_503.V2 1 | 2 |
| L5 | CallFunction_503.0 (distance) | PromotableOperator_22.A 0 | 2 |
| L6 | PromotableOperator_22.0 | IfThenElse_95.Condition 1 | 2 |
| L7 | CallFunction_497.0 (`Bdir`) | PromotableOperator_23.A 0 | 3 |
| L8 | CallFunction_455.0 (tête) | PromotableOperator_24.A 0 | 3 |
| L9 | PromotableOperator_24.0 | PromotableOperator_25.A 0 | 3 |
| L10 | PromotableOperator_23.0 | PromotableOperator_25.B 1 | 3 |
| L11 | PromotableOperator_25.0 | CallFunction_504.InVect 0 | 3 |
| L12 | VariableGet_286.0 (`C2BoxMin`) | CallFunction_504.InBoxMin 1 | 3 |
| L13 | VariableGet_287.0 (`C2BoxMax`) | CallFunction_504.InBoxMax 2 | 3 |
| L14 | IfThenElse_95.then 0 | CallFunction_505.execute 0 | 3 |
| L15 | CallFunction_455.0 (tête) | CallFunction_505.Start 1 | 3 |
| L16 | CallFunction_504.0 (`Desired2`) | CallFunction_505.End 2 | 3 |
| L17 | MakeArray_5.0 ([MC, CamRoom]) | CallFunction_505.ActorsToIgnore 6 | 3 |
| L18 | CallFunction_505.OutHit 1 | CallFunction_506.Hit 0 | 3 |
| L19 | CallFunction_506.Normal 6 | PromotableOperator_26.A 0 | 3 |
| L20 | CallFunction_506.Location 4 | PromotableOperator_27.A 0 | 3 |
| L21 | PromotableOperator_26.0 | PromotableOperator_27.B 1 | 3 |
| L22 | PromotableOperator_27.0 | CallFunction_507.A 0 | 3 |
| L23 | CallFunction_504.0 (`Desired2`) | CallFunction_507.B 1 | 3 |
| L24 | CallFunction_505.ReturnValue 2 | CallFunction_507.bPickA 2 | 3 |
| L25 | CallFunction_507.0 | CallFunction_508.InVect 0 | 3 |
| L26 | VariableGet_286.0 (`C2BoxMin`) | CallFunction_508.InBoxMin 1 | 3 |
| L27 | VariableGet_287.0 (`C2BoxMax`) | CallFunction_508.InBoxMax 2 | 3 |
| L28 | CallFunction_508.0 | VariableSet_66.C2Target 1 | 3 |
| L29 | CallFunction_505.then 0 | VariableSet_66.execute 0 | 3 |
`IfThenElse_95.else` 1 : laissé libre (fiche : « Faux → rien (fin) »).
### 1.5 Valeurs (`set_pin_value`, 6, toutes `{"returnValue":null}`, relues)
| Broche | Avant (relu à la création) | Après (relu) |
|---|---|---|
| PromotableOperator_22.B 1 | (neuf, `""`, joker) | `80.0` (`Float (double-précision)`) |
| PromotableOperator_23.B 1 | (neuf, `""`) | `60.0,60.0,60.0` |
| PromotableOperator_24.B 1 | (neuf, `""`) | `0.0,0.0,100.0` |
| CallFunction_505.Radius 3 | `0.0` | `20.0` |
| CallFunction_505.TraceChannel 4 | `TraceTypeQuery1` | `TraceTypeQuery2` |
| PromotableOperator_26.B 1 | (neuf, `""`) | `20.0,20.0,20.0` |
Valeurs non prescrites de 505, laissées par défaut et relues **identiques à 459 et 499** (F4 § 1.5) : bTraceComplex
`false`, DrawDebugType `None`, bIgnoreSelf `true`, TraceColor `(R=1,G=0,B=0,A=1)`, TraceHitColor `(R=0,G=1,B=0,A=1)`,
DrawTime `5.000000`. `IfThenElse_95.Condition` garde la valeur par défaut `true`, sans effet puisque la broche est liée (L6).
### 1.6 Relecture et chaîne obtenue
`get_node_infos` final groupé sur les 21 nœuds touchés ou réutilisés : les 15 créés, plus 61, 62, 455, 497, `MakeArray_5`,
286 et 287. Les 29 liens apparaissent des deux côtés et les 6 valeurs sont relues. Types : vecteurs `Vector`, `bPickA`
et Condition `Booléen`, distance et PO22 `Float (double-précision)`, `Radius` `Float (simple précision)`. Liens non
touchés relus intacts : 61.execute ← `IfThenElse_90`.0, 61.C2Target ← 496 ; 62.execute ← `IfThenElse_90`.1,
62.C2Target ← 495 ; 455.self ← 264, `head` ; 455 → 457, 459, 464, 473, 499 (plus 503, PO24, 505) ; 497 ← PO17, 288,
Axis (0,0,1), 497 → PO3.A (plus PO23) ; `MakeArray_5` → 459.6, 499.6 (plus 505.6), [0] ← 261, [1] ← 268 ; 286 / 287 →
495, 496, 502 (plus 504, 508). Aucune divergence.
Chaîne obtenue en fin de `ComputeC2Target` : `IfThenElse_90` (impact / sans impact) → `Définir C2Target` (61 ou 62)
→ Branche 95 (`Distance(C2Target, tête) < 80`). Si vrai : `SphereTraceByChannel(tête → Desired2, r 20,
TraceTypeQuery2, ignorer [MC, CamRoom] + self)` (505), puis `Définir C2Target` (66) := `Bound(touché ? Location +
Normal × 20 : Desired2, C2BoxMin, C2BoxMax)`, avec `Desired2 = Bound(tête + (0,0,100) + Bdir × 60, C2BoxMin, C2BoxMax)`
(504). Si faux : fin, et `C2Target` garde la valeur de 61 ou 62, comme après F4.
### 1.7 Compilation
`compile_blueprint {blueprint:{refPath:"/Game/BPs/Room.Room"}, warnings_as_errors:true}` → `{"returnValue":null}`,
aucune exception (critère de la rubrique « Fin de chaque fiche »). `hyper_blueprint_debug_inspect` non appelé (absent
du serveur le 2026-10-10, mémoire `unreal-mcp-reconnect` ; non revérifié). Journal de l'éditeur non lu : le chemin
`-abslog` n'a pas été fourni. Pas de `save_assets` (réservé à F7).
## 2. Écarts à la SPEC
- Aucun écart de câblage : la ligne B2b-3 (`CAM-SPEC.md:377`) et la fiche F5 (`CAM-B2b-FICHES.md:115-125`) sont
réalisées telles quelles (points 1 à 3) ; aucun nœud hors fiche touché ; aucun lien existant coupé.
- `Bdir × 60` et `Hit.Normal × 20` (SPEC, scalaires) sont réalisés par `vector*vector` avec B = (60,60,60) et
(20,20,20), comme le prescrit la fiche : c'est équivalent composante par composante.
- « Location » est la sortie `Location` (4) de `BreakHitResult`, centre de la sphère au contact, et non `ImpactPoint`
(5) : même choix que 460 → PO7 (ComputeC2Target) et 500 → PO21 (F4).
- Seuil 80 : `float<float` en double précision (la sortie de `Distance(Vector)` est en double), B = `80.0`.
- Garde `Accessed None` : aucune `IsValid` ajoutée, car la fiche n'en demande pas. Les nœuds neufs ne lisent aucune
référence d'objet : vecteurs, structure de touche, booléen. `MakeArray_5` est réutilisé tel quel, comme en 459 et 499.
`SelectVector` est pur et évalue A et B, mais aucun des deux ne déréférence d'objet : aucune cascade de branches n'est
requise. En revanche, 455 (`GetSocketLocation`, self ← `VariableGet_264`) est désormais lu en plus par 503 (condition)
et par 505 (Start, puis End via PO24). Si sa cible est nulle, un `Accessed None` déjà présent serait compté plus
souvent (point 4 du § 5).
- Ordre des écritures : chaque `set_pin_value` d'un opérateur a été posé juste après la liaison de son A, qui le type
(comme en F3 et F4). Typage et valeurs sont confirmés à la relecture finale (§ 1.6).
- Positions des nœuds : choisies hors des nœuds existants (cosmétique, non prescrit).
## 3. Instantané
Fait par l'orchestrateur avant F1 (non refait, consigne). Manifeste relu et disque mesuré après F5 :
```
date -Iseconds; md5sum "/d/Game/LifePlay-master 5.8/Content/BPs/Room.uasset"; grep -i "Room.uasset" "/d/Game/LifePlay_Backup_5.5/CAM-B2b/manifest.csv"
2026-10-13T15:56:18+02:00
a5fa970e821dc2d0d9bf220fd43b9de6 */d/Game/LifePlay-master 5.8/Content/BPs/Room.uasset
"Content\BPs\Room.uasset","True","6060745","A5FA970E821DC2D0D9BF220FD43B9DE6","2026-10-13T15:25:45"
```
Le MD5 du disque est celui de l'instantané : rien n'a été enregistré. Retour arrière avant F7 : fermer l'éditeur sans
enregistrer, ce qui perd F1 à F5. Après F7 : `Tools\Restore.ps1 -Lot CAM-B2b -Only Content\BPs\Room.uasset`, éditeur
fermé, sur décision de l'orchestrateur (jamais lancé ici).
## 4. Ce qui n'a pas été fait
- F6 et F7 (pilotage, compilation finale, enregistrement) : hors périmètre.
- `hyper_blueprint_debug_inspect`, journal de l'éditeur : non consultés (§ 1.7).
- `save_assets` : interdit avant F7 ; F1 à F5 vivent en mémoire de l'éditeur PID 10708 (une fermeture ou un plantage
avant F7 les perd ; l'instantané reste intact).
- Comportement à l'exécution : non mesuré (aucune PIE, aucun build) ; seulement déduit du câblage.
- Preuve en jeu (build empaqueté + `LogStats`) : hors rôle.
## 5. Points à confirmer en VAL
1. Cas « distance ≥ 80 » : 95 sort par `else` (libre), donc `C2Target` = valeur de 61 ou 62, comme après F4 ; comportement
inchangé hors repli (établi par le câblage ; à confirmer en jeu).
2. Changement voulu (distance < 80) : la cible passe à `Bound(tête + (0,0,100) + Bdir × 60)`, ou au point de contact
reculé de 20 le long de la normale, toujours borné par `C2BoxMin` / `C2BoxMax`. À confirmer en jeu : près d'un mur,
C2 se replie vers le haut et vers l'intérieur, sans sortir de la pièce.
3. `Bdir` unitaire et horizontal (estimé) : 497 = `RotateVectorAroundAxis(Normalize2D(Fwd) × −1, C2Yaw, (0,0,1))`
(F3) ; `Normalize2D` rend Z = 0 et une rotation autour de Z garde la norme. `Desired2` serait donc à 60 cm en
arrière (horizontal) et à 100 cm au-dessus de la tête, soit environ 117 cm, avant la borne (non lu dans le moteur).
4. `LogStats` : aucun `Accessed None` nouveau, en particulier sur `VariableGet_264` (cible de 455), désormais lu aussi
par 503 et 505.
5. Un seul passage : si la borne ou la touche ramènent la cible à moins de 80 cm, rien ne relance le repli (pas de
boucle, voulu par la SPEC). À observer en jeu dans un coin bas de plafond.
6. Ordre d'exécution : `ComputeC2Target` (CE47) est appelé par 467 (poursuite) avant la trace 499 (F4) et par
`PlaceC2`. Le repli s'exécute donc dans le même appel, avant que 499 et 474 lisent `C2Target` (estimé : un événement
appelé s'exécute de façon synchrone).
7. Valeurs sérialisées après `save_assets` (F7), par dump (`LPDumpFunction`) : `505.Radius = 20`,
`505.TraceChannel = TraceTypeQuery2`, `PO22.B = 80`, `PO23.B = (60,60,60)`, `PO24.B = (0,0,100)`,
`PO26.B = (20,20,20)`.
8. V5 (`CAM-SPEC.md:382`) : `SphereTraceSingle` 3 (459, 499, 505) ; `Vector_BoundedToBox` 5 (495, 496, 502, 504,
508 ; attendu ≥ 4) ; `Vector_Distance` 1 (503) ; `RotateAngleAxis` 1 (497).
9. Compilation stricte jugée sur l'absence d'exception seulement ; recontrôle en F7 et par `CompileAllBlueprints`.
## 6. Fichiers à commiter
- `A Docs/Migration/etat/CAM/CAM-B2b-IMPL-F5.md` (dépôt du jeu, branche `ue5.8`).
- `Content/BPs/Room.uasset` : rien à commiter pour F5 (non enregistré) ; il le sera après F7 et la VAL.
Tours : 62 / 60 (ce Write et la remise du compte rendu compris ; dépassement de 2 dans la marge `maxTurns`, sans
étape ouverte après le budget : la compilation a eu lieu au tour 59)
## Constats
- `Utilitaires|Opérateurs|Inférieurà(<)` se crée directement par `create_node` (pas besoin de `find_node_types`) ; à
la création, il est relu `Math|Durée|Timespan<Timespan`, broches joker. Relié en A à un double, il devient
`Math|Flottant|float<float` et accepte aussitôt `set_pin_value` B = "80.0".
- `Math|Vecteur|Distance(Vector)` : V1 0, V2 1 ; sortie 0 en `Float (double-précision)`.
- `Variables|Pardéfaut|ObtenirC2Target` → `|GetC2Target` (sortie 0) ; `DéfinirC2Target` → `|SetC2Target` (execute 0,
C2Target 1 ; then 0, Output_Get 1).
- Une Branche neuve a Condition = `true` par défaut.
- Économie : 1 lecture des existants, création de tous les nœuds, 1 lecture groupée, câblage et valeurs, 1 relecture
finale (21 nœuds), compilation. Au total, 54 appels pour 15 nœuds, 29 liens et 6 valeurs. Avec 5 tours de lecture
des consignes, le budget de 60 est juste : une fiche de cette taille devrait compter environ 65 tours.