16 KiB
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 desave_assetsavant F7). Preuve : MD5 disque après F5 = MD5 de l'instantané (§ 3).- Graphe
/Game/BPs/Room.Room:EventGraph, fin deComputeC2Target(CE47), aprèsVariableSet_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 × 60etHit.Normal × 20(SPEC, scalaires) sont réalisés parvector*vectoravec 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) deBreakHitResult, centre de la sphère au contact, et nonImpactPoint(5) : même choix que 460 → PO7 (ComputeC2Target) et 500 → PO21 (F4). - Seuil 80 :
float<floaten double précision (la sortie deDistance(Vector)est en double), B =80.0. - Garde
Accessed None: aucuneIsValidajouté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_5est réutilisé tel quel, comme en 459 et 499.SelectVectorest 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, unAccessed Nonedéjà présent serait compté plus souvent (point 4 du § 5). - Ordre des écritures : chaque
set_pin_valued'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
- Cas « distance ≥ 80 » : 95 sort par
else(libre), doncC2Target= valeur de 61 ou 62, comme après F4 ; comportement inchangé hors repli (établi par le câblage ; à confirmer en jeu). - 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é parC2BoxMin/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. Bdirunitaire et horizontal (estimé) : 497 =RotateVectorAroundAxis(Normalize2D(Fwd) × −1, C2Yaw, (0,0,1))(F3) ;Normalize2Drend Z = 0 et une rotation autour de Z garde la norme.Desired2serait 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).LogStats: aucunAccessed Nonenouveau, en particulier surVariableGet_264(cible de 455), désormais lu aussi par 503 et 505.- 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.
- Ordre d'exécution :
ComputeC2Target(CE47) est appelé par 467 (poursuite) avant la trace 499 (F4) et parPlaceC2. Le repli s'exécute donc dans le même appel, avant que 499 et 474 lisentC2Target(estimé : un événement appelé s'exécute de façon synchrone). - 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). - V5 (
CAM-SPEC.md:382) :SphereTraceSingle3 (459, 499, 505) ;Vector_BoundedToBox5 (495, 496, 502, 504, 508 ; attendu ≥ 4) ;Vector_Distance1 (503) ;RotateAngleAxis1 (497). - 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, brancheue5.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 parcreate_node(pas besoin defind_node_types) ; à la création, il est reluMath|Durée|Timespan<Timespan, broches joker. Relié en A à un double, il devientMath|Flottant|float<floatet accepte aussitôtset_pin_valueB = "80.0".Math|Vecteur|Distance(Vector): V1 0, V2 1 ; sortie 0 enFloat (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 =
truepar 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.