Props whose source shape differs from the resolved value can't be validated client-side
_Surfaced while reviewing the client-side transform work in [!626](https://git.drupalcode.org/project/canvas/-/merge_requests/626#note_856340) (for #3574857): client-side validation was failing for a content-entity-reference prop, and digging into why turned up the broader source-vs-resolved shape issue below. See that MR thread for the full analysis._
### Overview
Some component props can't be meaningfully validated client-side against their JSON Schema, for two reasons:
1. **Source shape differs from the resolved shape.** The form edits a scalar (an entity/file/media id) that the server wraps into the prop's resolved object — documented in `docs/redux-integrated-field-widgets.md` §3.2.1 (e.g. image source `{target_id}` resolves to `{src, alt, width, height}`). The scalar can never satisfy the resolved `type: object` schema.
2. **Value assembled from multiple inputs.** The value is built from several controls (e.g. a date range's start/end, a link's URI + title), so it's incomplete until every sub-field is filled; validating per-keystroke fails spuriously.
Today there is only one mechanism, and it's incidental: a prop is skipped when it *happens* to render more than one form control. That covers image/file/media (reason 1) and date range/link (reason 2) — but by coincidence of form structure, not because anything declares why. A **single-input** object-shaped prop isn't covered at all.
This was surfaced by #3574857, which introduces exactly that gap: `entity_reference_autocomplete` editing a content-entity-reference prop — a single input whose scalar id resolves to an object. This issue provides the mechanism so that #3574857 (and any future widget) can declare the skip rather than special-case it; declaring the flag on `entity_reference_autocomplete` itself is part of #3574857, not this issue.
### Proposed resolution
Make both skips explicit:
1. **Source≠resolved** is a fixed property of the widget, so it is *declared*: a new optional `canvas.sourceShapeDiffersFromResolved` flag, alongside the existing `canvas.transforms`. Flagged props skip client-side validation regardless of how many inputs they render. Declared here on image, file and media — making the skip they already get today explicit. (#3574857 declares it on `entity_reference_autocomplete`, the single-input case that motivated this.)
2. **Multi-input** depends on widget configuration (a link's optional title, a datetime's granularity, cardinality), so it stays *detected from the rendered form*, not declared. Once reason 1 is flagged, this detection fires only for genuine composites (date range, link) and reads as an explicit reason — incomplete until all inputs are present — rather than a catch-all.
Behaviour is unchanged: it makes the existing incidental skips explicit and provides the mechanism #3574857 needs.
### Remaining tasks
- Declare `sourceShapeDiffersFromResolved` on image, file and media, and expose it to the client per prop.
- Skip client-side validation for flagged props.
- Reframe the multi-input skip as an explicit reason, distinct from reason 1.
- Document both skip reasons and the new widget-metadata key so contrib widget authors can opt in.
- Cover both skip reasons with tests.
### User interface changes
None in this issue. The change is behaviour-neutral.
### API changes
- Added: `canvas.sourceShapeDiffersFromResolved` — an optional boolean in a field widget's plugin definition metadata (sibling to `canvas.transforms`), set via `hook_field_widget_info_alter()`.
### Release notes snippet
Field widgets can declare `canvas.sourceShapeDiffersFromResolved` to tell Canvas their stored value has a different shape than the component prop's resolved value, deferring client-side validation to the server. Use it for widgets that edit a scalar reference (e.g. an entity id) that resolves to an object.
issue