210 lines
15 KiB
Markdown
210 lines
15 KiB
Markdown
|
|
Fiche CAM-B2m — Niveau N3 — Modèle prévu non précisé par la fiche | utilisé claude-opus-5-5 — Agent lp-mcp-bp (A-MCP-BP) — Skills sk-protocol, sk-change-safety, lp-mcp, lp-lot
|
|||
|
|
# CAM-B2m-IMPL : lacet POV à la souris, le rotateur 312 passe de Roll à Yaw et 136 appelle AddWorldRotation (2026-10-14)
|
|||
|
|
|
|||
|
|
Résultat : **réussi**, en un passage dans l'éditeur headless déjà lancé par l'orchestrateur (pid 1272, port 8000).
|
|||
|
|
- État lu conforme à la section « Cause » de la fiche. Aucun nœud créé, 1 coupure, 3 liens posés.
|
|||
|
|
- Relecture conforme à l'étape 5. `is_dirty` = vrai. Compilation stricte sans diagnostic. `save_assets` de PC seul.
|
|||
|
|
- PC passe de `a19510e6…` à `f45be57a…`. Room (`6be71e01…`), GI (`e64b5b37…`) et Person (`8668a47c…`) sont
|
|||
|
|
inchangés et n'ont pas été chargés.
|
|||
|
|
|
|||
|
|
Spécification : `Docs/Migration/etat/CAM/CAM-B2m-FICHE.md` ; origine : `CAM-COMMUN5-DIAG.md` § 3. Préfixe des
|
|||
|
|
nœuds : `/Game/BPs/PC.PC:EventGraph.`. Un seul appel MCP par message. Outils :
|
|||
|
|
`editor_toolset.toolsets.asset.AssetTools` (AT) et `editor_toolset.toolsets.blueprint.BlueprintTools` (BT).
|
|||
|
|
|
|||
|
|
Abréviations : `136`, `164`, `75`, `76` = `K2Node_IfThenElse_n` ; `204`, `312`, `314`, `316`, `951` =
|
|||
|
|
`K2Node_CallFunction_n` ; `108`, `53`, `66` = `K2Node_CommutativeAssociativeBinaryOperator_n` ; `67`, `115` =
|
|||
|
|
`K2Node_VariableGet_n`. PinID au format `{direction, index_id}` du nœud nommé.
|
|||
|
|
|
|||
|
|
## 1. Fichiers modifiés
|
|||
|
|
- `Content/BPs/PC.uasset` : aucun nœud créé ni supprimé ; 1 lien coupé, 3 liens posés, dont 2 qui remplacent les
|
|||
|
|
liens d'exécution vers 951.
|
|||
|
|
- Avant : MD5 `a19510e613f31905437bab48f38c6154` (3 404 928 octets).
|
|||
|
|
- Après : `f45be57a39d13d3eb19d0b543153ab0b` (3 404 786 octets, 2026-10-14 01:05:26 heure locale).
|
|||
|
|
- Journal de l'éditeur, l. 2335 : `LogFileHelpers: Saving Package: /Game/BPs/PC`. C'est la seule sauvegarde de
|
|||
|
|
cette fiche (l'autre ligne `Saving Package`, l. 2278, est Room, fiche B2k).
|
|||
|
|
- `Content/BPs/Room.uasset` = `6be71e0110c4187fa02d7ac9c1c92306`, `Content/BPs/GI.uasset` =
|
|||
|
|
`e64b5b37c9ef0db7735de0d6e3bd7c1c`, `Content/BPs/Person.uasset` = `8668a47c627f7a5254910cf0ac33b12a` : identiques
|
|||
|
|
au début de la fiche. Aucun des trois n'a été chargé par cette fiche (11 appels, tous listés au § 1.1).
|
|||
|
|
- `git status` marque Room, GI et Person `M` : déjà le cas au début de la fiche (B2k et lots précédents).
|
|||
|
|
- `Docs/Migration/etat/CAM/CAM-B2m-IMPL.md` : ce livrable.
|
|||
|
|
|
|||
|
|
### 1.1 Appels MCP, dans l'ordre
|
|||
|
|
| # | Appel | Arguments | Retour |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| 1 | AT.`load_asset` | `{asset_path:"/Game/BPs/PC"}` | `{"refPath":"/Game/BPs/PC.PC"}` |
|
|||
|
|
| 2 | BT.`get_node_infos` | `136`, `951`, `204`, `312`, `108`, `316`, `164` | état avant (§ 1.2) |
|
|||
|
|
| 3 | BT.`break_pins` (étape 2) | `108 {EGPD_Output,0}` (ReturnValue) → `312 {EGPD_Input,0}` (Roll) | `null` |
|
|||
|
|
| 4 | BT.`connect_pins` (étape 3) | `108 {EGPD_Output,0}` (ReturnValue) → `312 {EGPD_Input,2}` (Yaw) | `null` |
|
|||
|
|
| 5 | BT.`connect_pins` (étape 4a) | `136 {EGPD_Output,0}` (then) → `204 {EGPD_Input,0}` (execute) | `null` |
|
|||
|
|
| 6 | BT.`get_node_infos` | `136` | then → `204` [0] seul : le lien vers 951 a été remplacé ; else → `951` [0] encore |
|
|||
|
|
| 7 | BT.`connect_pins` (étape 4b) | `136 {EGPD_Output,1}` (else) → `204 {EGPD_Input,0}` (execute) | `null` |
|
|||
|
|
| 8 | BT.`get_node_infos` (étape 5) | `136`, `951`, `204`, `312`, `108`, `316`, `164` | relecture conforme (§ 1.3) |
|
|||
|
|
| 9 | AT.`is_dirty` | `{asset_path:"/Game/BPs/PC"}` | `true` |
|
|||
|
|
| 10 | BT.`compile_blueprint` | `{blueprint:{refPath:"/Game/BPs/PC.PC"}, warnings_as_errors:true}` | `null` (pas d'exception) |
|
|||
|
|
| 11 | AT.`save_assets` | `{asset_paths:["/Game/BPs/PC"]}` | `true`, confirmé par le journal et le MD5 |
|
|||
|
|
|
|||
|
|
PinID complets des écritures, avec `node:{refPath:"/Game/BPs/PC.PC:EventGraph.K2Node_<Nom>"}` :
|
|||
|
|
- appel 3 : `output_pin {direction:"EGPD_Output", index_id:0, node:…CommutativeAssociativeBinaryOperator_108}`,
|
|||
|
|
`input_pin {direction:"EGPD_Input", index_id:0, node:…CallFunction_312}` ;
|
|||
|
|
- appel 4 : même `output_pin`, `input_pin {direction:"EGPD_Input", index_id:2, node:…CallFunction_312}` ;
|
|||
|
|
- appel 5 : `output_pin {direction:"EGPD_Output", index_id:0, node:…IfThenElse_136}`,
|
|||
|
|
`input_pin {direction:"EGPD_Input", index_id:0, node:…CallFunction_204}` ;
|
|||
|
|
- appel 7 : `output_pin {direction:"EGPD_Output", index_id:1, node:…IfThenElse_136}`, même `input_pin`.
|
|||
|
|
|
|||
|
|
Index relevés à l'appel 2, avant toute écriture : 312 Roll `{EGPD_Input,0}`, Pitch `{EGPD_Input,1}`, Yaw
|
|||
|
|
`{EGPD_Input,2}` (tous `Float (simple précision)`), ReturnValue `{EGPD_Output,0}` ; 204 execute `{EGPD_Input,0}`,
|
|||
|
|
self `{EGPD_Input,1}`, DeltaRotation `{EGPD_Input,2}`, then `{EGPD_Output,0}`.
|
|||
|
|
|
|||
|
|
Aucun `create_node`, `delete_node` ni `set_pin_value`. Aucune écriture par HyperAIStudio ; aucun outil `hyper_*` appelé.
|
|||
|
|
Aucun autre asset chargé. Le journal de l'éditeur compte 11 lignes `Dispatching toolset tool` de plus qu'au début
|
|||
|
|
(13 → 24), une par appel ci-dessus, dans le même ordre (l. 2311 à 2333).
|
|||
|
|
|
|||
|
|
### 1.2 État lu avant écriture (appel 2), comparé à la section « Cause »
|
|||
|
|
| Nœud | type_id, position | Lu | Fiche |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| `136` Branche | `Utilitaires|ContrôleDeFlux|Branche`, (3424, 3120) | execute ← `75` [1] ; Condition ← `53` [0] ; then `{EGPD_Output,0}` → `951` [0] ; else `{EGPD_Output,1}` → `951` [0] | conforme |
|
|||
|
|
| `951` | `Transformation|AddRelativeRotation`, (3744, 3744) | execute ← `136` [0] et [1] ; self ← `67` [0] ; DeltaRotation ← `312` [0] ; bSweep, bTeleport `false` ; then et SweepHitResult vides | conforme |
|
|||
|
|
| `204` | `Transformation|AddWorldRotation`, (4016, 3728) | execute **vide** ; self ← `67` [0] ; DeltaRotation ← `312` [0] ; bSweep, bTeleport `false` ; then et SweepHitResult vides | conforme (nœud mort) |
|
|||
|
|
| `312` | `Math|Rotateur|MakeRotator`, (3344, 3760) | Roll ← `108` [0] ; Pitch `0.0` non relié ; Yaw `0.0` non relié ; ReturnValue → `204` [2], `951` [2] | conforme |
|
|||
|
|
| `108` | `Math|Flottant|float*float`, (3136, 3744) | A ← `115` [0] ; B = `-1` ; ReturnValue → `312` [0] seul | conforme |
|
|||
|
|
| `316` | `Transformation|AddWorldRotation`, (3968, 4480) | execute ← `164` [0] et [1] ; self ← `67` [0] ; DeltaRotation ← `314` [0] ; then vide | conforme |
|
|||
|
|
| `164` Branche | (4016, 4688) | execute ← `76` [1] ; Condition ← `66` [0] ; then et else → `316` [0] | conforme |
|
|||
|
|
|
|||
|
|
Aucun écart : pas d'arrêt.
|
|||
|
|
|
|||
|
|
### 1.3 Relecture (appels 6 et 8) : avant et après
|
|||
|
|
| Broche (PinID) | Avant | Après |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `136` then `{EGPD_Output,0}` | → `951` [0] | **→ `204` [0]** (seul lien) |
|
|||
|
|
| `136` else `{EGPD_Output,1}` | → `951` [0] | **→ `204` [0]** (seul lien) |
|
|||
|
|
| `136` execute / Condition | ← `75` [1] / ← `53` [0] | identique |
|
|||
|
|
| `951` execute `{EGPD_Input,0}` | ← `136` [0], [1] | **vide** (nœud laissé en place, mort) |
|
|||
|
|
| `951` self / DeltaRotation / then | ← `67` / ← `312` / vide | identique |
|
|||
|
|
| `204` execute `{EGPD_Input,0}` | vide | **← `136` [0], `136` [1]** |
|
|||
|
|
| `204` self / DeltaRotation / then | ← `67` / ← `312` / vide | identique |
|
|||
|
|
| `312` Roll `{EGPD_Input,0}` | ← `108` [0] | **`0.0`, non relié** |
|
|||
|
|
| `312` Pitch `{EGPD_Input,1}` | `0.0`, non relié | identique |
|
|||
|
|
| `312` Yaw `{EGPD_Input,2}` | `0.0`, non relié | **← `108` [0]** |
|
|||
|
|
| `312` ReturnValue `{EGPD_Output,0}` | → `204` [2], `951` [2] | identique |
|
|||
|
|
| `108` ReturnValue `{EGPD_Output,0}` | → `312` [0] | **→ `312` [2]** (seul lien) ; A ← `115`, B `-1` identiques |
|
|||
|
|
| `316`, `164` | § 1.2 | identiques, broche par broche |
|
|||
|
|
|
|||
|
|
Comportement attendu : en POV, la branche 136 appelle désormais `FirstPersonSM.K2_AddWorldRotation(MakeRotator(Roll 0,
|
|||
|
|
Pitch 0, Yaw = leftright × −1))`, soit un lacet autour de l'axe Z du monde, au lieu d'un Roll relatif. 136.then et
|
|||
|
|
136.else mènent au même appel, comme avant (seul le nœud cible change). Le vertical (164 → 316) n'est pas touché.
|
|||
|
|
|
|||
|
|
Garde `Accessed None` (lp-mcp § 1 règle 4) : aucun `IsValid` ajouté, la fiche n'en prévoit pas. 204 lit
|
|||
|
|
`67` (`FirstPersonSM`), la même référence que 951 lisait déjà et que 316 lit pour le vertical : aucune lecture nouvelle.
|
|||
|
|
|
|||
|
|
### 1.4 Compilation et sauvegarde (journal `D:\Game\LifePlay_Backup_5.5\CAM-B2kmn\editeur\editeur-B2kmn.log`)
|
|||
|
|
- 2309 lignes au début de la fiche, 2327 avant la compilation ; 1 ligne `Saving Package` avant (Room, l. 2278).
|
|||
|
|
- Appel 10 : l. 2331, `LogBlueprint: Compiling Blueprint '/Game/BPs/PC.PC'`. Puis 0 ligne `error` ou `warning`
|
|||
|
|
(insensible à la casse) de la l. 2310 à la fin (l. 2364), compilation, sauvegarde et validation comprises.
|
|||
|
|
- `hyper_blueprint_debug_inspect` n'a pas été appelé : il est absent du serveur (repli prévu : `warnings_as_errors`
|
|||
|
|
et le journal).
|
|||
|
|
- Sauvegarde, l. 2335 : `Saving Package: /Game/BPs/PC`. Puis `Moving '…/Saved/PC4484A5FD427A93DC50FE4CA8B5BEC006.tmp'
|
|||
|
|
to '…/Content/BPs/PC.uasset'` et `AssetCheck: /Game/BPs/PC Validation de la ressource`.
|
|||
|
|
- La procédure B2f-a (Branche isolée créée puis supprimée) n'a pas servi : `is_dirty` était vrai après les écritures.
|
|||
|
|
|
|||
|
|
## 2. Écarts à la SPEC
|
|||
|
|
- Aucun écart sur l'état lu, les PinID, les écritures ni la relecture.
|
|||
|
|
- Ajout : une relecture de `136` (appel 6) entre les deux `connect_pins` de l'étape 4, pour vérifier que le lien `then`
|
|||
|
|
remplaçait bien celui vers 951 avant de poser le lien `else`. Lecture seule.
|
|||
|
|
- Instantané : la fiche prévoit le retour par `-Lot CAM-B2m` ; l'orchestrateur a pris l'instantané sous `CAM-B2kmn`
|
|||
|
|
(Room et PC). Le retour arrière de la fiche est donc à lire `-Lot CAM-B2kmn -Only Content\BPs\PC.uasset` (§ 3).
|
|||
|
|
- Room, GI et Person n'ont pas été ouverts. Ni build, ni commandlet, ni jeu. L'éditeur n'a été ni lancé ni arrêté.
|
|||
|
|
|
|||
|
|
## 3. Instantané
|
|||
|
|
- `D:\Game\LifePlay_Backup_5.5\CAM-B2kmn\manifest.csv` (pris par l'orchestrateur), relu :
|
|||
|
|
`"Content\BPs\PC.uasset","True","3404928","A19510E613F31905437BAB48F38C6154","2026-10-14T00:59:11"` (et la ligne de
|
|||
|
|
Room, `18565365…`, fiche B2k).
|
|||
|
|
- MD5 de PC sur le disque avant l'appel 1 = celui du manifeste.
|
|||
|
|
- Retour arrière **proposé, non lancé**, par l'orchestrateur, éditeur fermé, sur accord (PC seul ; Room a sa propre
|
|||
|
|
ligne, fiche B2k) :
|
|||
|
|
1. `.\Tools\Snapshot.ps1 -Lot CAM-B2kmn-retour -Path Content\BPs\PC.uasset` ;
|
|||
|
|
2. `.\Tools\Restore.ps1 -Lot CAM-B2kmn -Only Content\BPs\PC.uasset -WhatIf` ;
|
|||
|
|
3. `.\Tools\Restore.ps1 -Lot CAM-B2kmn -Only Content\BPs\PC.uasset`.
|
|||
|
|
Contrôle : `md5sum Content/BPs/PC.uasset` = `a19510e6…`.
|
|||
|
|
- Entrée : `2026-10-14 | CAM-B2m, lacet POV (312 Roll → Yaw ; 136 then/else → 204 AddWorldRotation) |
|
|||
|
|
Content/BPs/PC.uasset | retour arrière : Restore.ps1 -Lot CAM-B2kmn -Only Content\BPs\PC.uasset | instantané :
|
|||
|
|
D:\Game\LifePlay_Backup_5.5\CAM-B2kmn | vérification : relecture conforme, compilation stricte 0 diagnostic,
|
|||
|
|
PC = f45be57a…`.
|
|||
|
|
|
|||
|
|
## 4. Ce qui n'a pas été fait
|
|||
|
|
- `VariableGet_115` (A de 108) n'a pas été relu par nom : qu'il s'agisse de `leftright` vient du dump de la fiche
|
|||
|
|
(`CAM-B1-VAL_LPDumpFunction_20261013-085611.txt`), non relu ici. `53` (Condition de 136), `75` et `67` non plus.
|
|||
|
|
- 951 n'est pas supprimé (fiche : « laissé en place, mort »).
|
|||
|
|
- Le sens de rotation (B de 108 = `-1`) n'est pas modifié : réserve de la fiche, à trancher à l'essai.
|
|||
|
|
- `is_dirty` n'a pas été relu après la sauvegarde (la fiche ne le demande pas).
|
|||
|
|
- `CompileAllBlueprints` éditeur fermé, build empaqueté, `LogStats`, essai en jeu : hors fiche (lp-mcp § 1 règles 3 et 5).
|
|||
|
|
- L'éditeur n'est pas fermé (rôle de l'orchestrateur, puis `BUILD-FIN`).
|
|||
|
|
|
|||
|
|
## 5. Points à confirmer en VAL
|
|||
|
|
- PC = `f45be57a39d13d3eb19d0b543153ab0b` ; Room = `6be71e01…`, GI = `e64b5b37…`, Person = `8668a47c…` inchangés.
|
|||
|
|
- V5, diff de l'EventGraph de PC contre le dump de B1-VAL limité à :
|
|||
|
|
- `312` : `108` relié à Yaw au lieu de Roll ;
|
|||
|
|
- `136` then et else → `204` au lieu de `951` ; `951` execute vide ; `204` execute ← `136` (deux liens) ;
|
|||
|
|
- aucun nœud nouveau ni supprimé.
|
|||
|
|
- `316`, `164` et le reste de l'EventGraph inchangés.
|
|||
|
|
- V6 : `CompileAllBlueprints` éditeur fermé = référence (PC sans erreur ni avertissement nouveau, malgré 951 mort).
|
|||
|
|
- V7 (COMMUN-6) : en POV, souris horizontale = rotation de la vue (lacet), sans pente. Si le sens est inversé :
|
|||
|
|
réserve de la fiche (`set_pin_value` `108.B` = `1`). Tangage 316 juste face à X, faux face à Y : non traité, à noter.
|
|||
|
|
- V7 : `LogStats` sans `Accessed None` nouveau sur `PC` (204 lit `FirstPersonSM` comme 951 et 316 avant lui).
|
|||
|
|
|
|||
|
|
## 6. Fichiers à commiter
|
|||
|
|
- M `Content/BPs/PC.uasset` (dépôt du jeu, branche ue5.8).
|
|||
|
|
- A `Docs/Migration/etat/CAM/CAM-B2m-IMPL.md` (dépôt du jeu, branche ue5.8).
|
|||
|
|
- Pas Room, GI ni Person : leur `M` vient de B2k et de lots antérieurs.
|
|||
|
|
|
|||
|
|
## Mesuré
|
|||
|
|
```
|
|||
|
|
$ md5sum Content/BPs/PC.uasset Content/BPs/Room.uasset Content/BPs/GI.uasset Content/BPs/Person.uasset (avant l'appel 1)
|
|||
|
|
a19510e613f31905437bab48f38c6154 *Content/BPs/PC.uasset
|
|||
|
|
6be71e0110c4187fa02d7ac9c1c92306 *Content/BPs/Room.uasset
|
|||
|
|
e64b5b37c9ef0db7735de0d6e3bd7c1c *Content/BPs/GI.uasset
|
|||
|
|
8668a47c627f7a5254910cf0ac33b12a *Content/BPs/Person.uasset
|
|||
|
|
$ wc -l editeur-B2kmn.log ; grep -n "Saving Package" ; grep -c "Dispatching toolset tool" (avant l'appel 1)
|
|||
|
|
2309 /d/Game/LifePlay_Backup_5.5/CAM-B2kmn/editeur/editeur-B2kmn.log
|
|||
|
|
2278:[2026.10.13-23.01.50:880][326]LogFileHelpers: Saving Package: /Game/BPs/Room
|
|||
|
|
13
|
|||
|
|
$ wc -l ; grep -c "Saving Package" ; grep -c "Dispatching toolset tool" (avant l'appel 10)
|
|||
|
|
2327 /d/Game/LifePlay_Backup_5.5/CAM-B2kmn/editeur/editeur-B2kmn.log
|
|||
|
|
1
|
|||
|
|
22
|
|||
|
|
$ tail -n +2328 editeur-B2kmn.log (après l'appel 10)
|
|||
|
|
[2026.10.13-23.05.18:083][193]LogModelContextProtocol: Running tool: 'call_tool'
|
|||
|
|
[2026.10.13-23.05.18:083][193]LogModelContextProtocol: Dispatching toolset tool: 'editor_toolset.toolsets.blueprint.BlueprintTools.compile_blueprint'
|
|||
|
|
[2026.10.13-23.05.18:083][193]LogBlueprint: Compiling Blueprint '/Game/BPs/PC.PC'
|
|||
|
|
[2026.10.13-23.05.19:153][193]LogUObjectHash: Compacting FUObjectHashTables data took 4.22ms
|
|||
|
|
$ grep -n "Saving Package" editeur-B2kmn.log (après l'appel 11)
|
|||
|
|
2278:[2026.10.13-23.01.50:880][326]LogFileHelpers: Saving Package: /Game/BPs/Room
|
|||
|
|
2335:[2026.10.13-23.05.26:489][534]LogFileHelpers: Saving Package: /Game/BPs/PC
|
|||
|
|
$ tail -n +2310 editeur-B2kmn.log | grep -ciE "error|warning" (après l'appel 11, fin = l. 2364)
|
|||
|
|
0
|
|||
|
|
$ md5sum Content/BPs/PC.uasset Content/BPs/Room.uasset Content/BPs/GI.uasset Content/BPs/Person.uasset (après l'appel 11)
|
|||
|
|
f45be57a39d13d3eb19d0b543153ab0b *Content/BPs/PC.uasset
|
|||
|
|
6be71e0110c4187fa02d7ac9c1c92306 *Content/BPs/Room.uasset
|
|||
|
|
e64b5b37c9ef0db7735de0d6e3bd7c1c *Content/BPs/GI.uasset
|
|||
|
|
8668a47c627f7a5254910cf0ac33b12a *Content/BPs/Person.uasset
|
|||
|
|
$ stat -c "%s %y %n" Content/BPs/PC.uasset Content/BPs/Room.uasset
|
|||
|
|
3404786 2026-10-14 01:05:26.870457900 +0200 Content/BPs/PC.uasset
|
|||
|
|
6391327 2026-10-14 01:01:51.899749700 +0200 Content/BPs/Room.uasset
|
|||
|
|
$ git status --short -- Content/BPs/
|
|||
|
|
M Content/BPs/GI.uasset
|
|||
|
|
M Content/BPs/PC.uasset
|
|||
|
|
M Content/BPs/Person.uasset
|
|||
|
|
M Content/BPs/Room.uasset
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Tours : 23 / 60
|
|||
|
|
|
|||
|
|
## Constats
|
|||
|
|
- `connect_pins` sur une sortie d'exécution déjà reliée **remplace** le lien (vérifié à l'appel 6 : 136.then ne
|
|||
|
|
mène plus qu'à 204) ; l'entrée d'exécution de 951 s'est vidée seule après les deux remplacements. Aucun
|
|||
|
|
`break_pins` préalable n'est nécessaire.
|
|||
|
|
- `break_pins` puis `connect_pins` suffisent à marquer l'asset modifié (`is_dirty` = vrai) : la procédure B2f-a
|
|||
|
|
n'a pas servi ici.
|
|||
|
|
- La broche Roll de 312 garde `0.0` après la coupure (valeur par défaut, relue à l'appel 8).
|
|||
|
|
- À verser dans lp-mcp § 3 : `connect_pins` sur une sortie d'exécution reliée remplace le lien existant (pas de
|
|||
|
|
`break_pins` préalable) ; `break_pins` / `connect_pins` marquent l'asset modifié (`is_dirty` vrai, CAM-B2m).
|