diff --git a/Inventory_frontend b/Inventory_frontend
index 767c9a7..a741596 160000
--- a/Inventory_frontend
+++ b/Inventory_frontend
@@ -1 +1 @@
-Subproject commit 767c9a7424cdc4f66c6d77fa1377fe93bdfdb837
+Subproject commit a7415964a718bef7c08af6d6399afd778e45b841
diff --git a/docs/superpowers/plans/2026-03-26-machine-single-save.md b/docs/superpowers/plans/2026-03-26-machine-single-save.md
new file mode 100644
index 0000000..7f16058
--- /dev/null
+++ b/docs/superpowers/plans/2026-03-26-machine-single-save.md
@@ -0,0 +1,1074 @@
+# Machine Single Save Button + Link Versioning — Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+**Goal:** Replace the machine page's auto-save-on-blur with a single "Enregistrer les modifications" button (matching composant/pièce/produit pages), and add versioning for machine link add/remove operations.
+
+**Architecture:** Frontend changes remove all `@blur` save triggers from MachineInfoCard, consolidate saves into a single `submitEdition()` method in the orchestrator composable, and add Save/Cancel buttons at the bottom of the page. MachineInfoCard exposes `saveFieldDefinitions()` via `defineExpose` so the parent can call it during submit. Backend changes extend `MachineAuditSubscriber`'s `onFlush` to detect link entity insertions/deletions and create audit entries on the parent machine.
+
+**Tech Stack:** Vue 3 / Nuxt 4, Symfony 8, Doctrine ORM, PHP 8.4
+
+---
+
+## File Structure
+
+| Action | File | Responsibility |
+|--------|------|----------------|
+| Modify | `Inventory_frontend/app/components/machine/MachineInfoCard.vue` | Remove blur-triggered saves, expose saveFieldDefinitions via defineExpose |
+| Modify | `Inventory_frontend/app/components/machine/MachineCustomFieldDefEditor.vue` | Remove standalone save button |
+| Modify | `Inventory_frontend/app/pages/machine/[id].vue` | Add Save/Cancel buttons, wire submitEdition via template ref |
+| Modify | `Inventory_frontend/app/composables/useMachineDetailData.ts` | Add submitEdition, cancelEdition, saving, canSubmit |
+| Modify | `Inventory_frontend/app/composables/useMachineDetailUpdates.ts` | Remove auto-save from handleMachineConstructeurChange |
+| Modify | `Inventory_frontend/app/composables/useMachineDetailCustomFields.ts` | Add saveAllMachineCustomFields batch method |
+| Modify | `src/EventSubscriber/MachineAuditSubscriber.php` | Enrich snapshot with links + detect link changes in onFlush |
+
+---
+
+### Task 1: Remove blur-triggered saves from MachineInfoCard
+
+**Files:**
+- Modify: `Inventory_frontend/app/components/machine/MachineInfoCard.vue`
+
+- [ ] **Step 1: Remove `@blur` from name input (line 17)**
+
+Replace:
+```vue
+ @input="$emit('update:machine-name', ($event.target as HTMLInputElement).value)"
+ @blur="$emit('blur-field')"
+```
+With:
+```vue
+ @input="$emit('update:machine-name', ($event.target as HTMLInputElement).value)"
+```
+
+- [ ] **Step 2: Remove `$emit('blur-field')` from site select (line 31)**
+
+Replace:
+```vue
+ @change="$emit('update:machine-site-id', ($event.target as HTMLSelectElement).value); $emit('blur-field')"
+```
+With:
+```vue
+ @change="$emit('update:machine-site-id', ($event.target as HTMLSelectElement).value)"
+```
+
+- [ ] **Step 3: Remove `@blur` from reference input (line 57)**
+
+Replace:
+```vue
+ @input="$emit('update:machine-reference', ($event.target as HTMLInputElement).value)"
+ @blur="$emit('blur-field')"
+```
+With:
+```vue
+ @input="$emit('update:machine-reference', ($event.target as HTMLInputElement).value)"
+```
+
+- [ ] **Step 4: Remove `@blur` from all custom field inputs**
+
+For each custom field input, remove the `@blur="$emit('update-custom-field', field)"` line:
+- text input (line 118)
+- number input (line 127)
+- select (line 135)
+- boolean checkbox (line 152)
+- date input (line 163)
+
+- [ ] **Step 5: Remove `@save` handler from MachineCustomFieldDefEditor usage (line 187)**
+
+Replace:
+```vue
+
+```
+With:
+```vue
+
+```
+
+- [ ] **Step 6: Remove unused emit declarations and add defineExpose**
+
+Replace the `defineEmits` block (lines 222-231):
+```ts
+const emit = defineEmits<{
+ 'update:machine-name': [value: string]
+ 'update:machine-reference': [value: string]
+ 'update:machine-site-id': [value: string]
+ 'update:constructeur-ids': [ids: unknown]
+ 'blur-field': []
+ 'set-custom-field-value': [field: any, value: unknown]
+ 'update-custom-field': [field: any]
+ 'custom-fields-saved': []
+}>()
+```
+With:
+```ts
+const emit = defineEmits<{
+ 'update:machine-name': [value: string]
+ 'update:machine-reference': [value: string]
+ 'update:machine-site-id': [value: string]
+ 'update:constructeur-ids': [ids: unknown]
+ 'set-custom-field-value': [field: any, value: unknown]
+ 'custom-fields-saved': []
+}>()
+```
+
+Then, at the end of the `