Publishing a symmetrically-translated canvas_page 422s when a default-language edit changes a non-translatable component input
### Overview Publishing an auto-saved `canvas_page` fails with HTTP 422 when the default-language edit changed a non-translatable ("symmetric") component input — e.g. an image `width`/`loading` attribute, a section `padding_bottom`, or a `heading` component's `element` (h1-h6) — on a component instance that also exists in a non-default-language translation. `ApiAutoSaveController::post()` validates the entity (`getConflictAwareContentEntityViolations()` -> `$entity->validate()`) before `$entity->save()` runs `content_translation`'s presave field synchronizer. The auto-save snapshot applied in `applyAutoSaveTranslationSnapshots()` only ever carries the edited (default) translation, so the non-default translation's copy of the changed non-translatable input is still stale at validation time. `ComponentTreeSymmetricalTranslationConstraint` then rejects the publish: > Non-translatable component input key '<key>' in component '<uuid>' differs > from the default translation in the '<lang>' translation. ADR 0012 defines the intended order: "the decorator synchronizes inputs at save time; the constraint validates the result." The publish path validates the pre-sync intermediate state instead. ### Steps to reproduce 1. Enable `content_translation` for `canvas_page`, in symmetric mode (the `components` field's `tree` column group not translatable, `inputs` translatable). 2. Create a page with a component instance, and add a non-default-language translation of that page (same component, same non-translatable input value). 3. In the default-language editor, change a non-translatable input on that component instance (e.g. an enum like `element`, or an image `width`). Auto-save runs. 4. Publish. **Expected:** publish succeeds (HTTP 200); the non-default translation's copy of the non-translatable input converges to the new value. **Actual:** HTTP 422; `ComponentTreeSymmetricalTranslationConstraint` fails comparing the new default value against the stale translation. ### Proposed resolution In `ApiAutoSaveController::applyAutoSaveTranslationSnapshots()`, before returning the entity, invoke `content_translation.synchronizer`'s `synchronizeFields()` when the entity is translatable and has more than one translation, so the caller validates the post-sync (converged) state, matching ADR 0012's intended order. Idempotent: `content_translation`'s presave hook re-runs the same synchronization. Safe for asymmetric translations: the Canvas-specific synchronizer no-ops when a field is not in symmetric mode. ### User interface changes None. ### API changes None. ### Data model changes None.
issue