Resolve #3591785: Strengthen AutoSaveManager to generate stable hashes
Summary
This branch consolidates the typed-data normalization logic that AutoSaveManager and ComponentSourceBase previously duplicated into a single method, TypedDataHelper::castRawPhpTypes().
What changed and why
AutoSaveManager::normalizeEntity() (hash source) and ComponentSourceBase::castRawTypedConfigToPhpTypes() (component-shape normalization) each contained their own primitive-casting and traversal logic. These are merged into TypedDataHelper::castRawPhpTypes(), which already existed for the config typed-data path but was not wired into toStorableArray().
During consolidation, a reconstruction hazard was identified and fixed. Iterating a content-entity field item via getProperties() instantiates every non-computed property, including ones that hold no value. For example, an entity-reference item's target_uuid, which is NULL until a UUID is assigned. getCastedValue() coerces that NULL to ''.
When stored auto-save data containing an empty target_uuid was fed back into EntityStorage::create(), the bundle reference no longer resolved (->type->entity became null), causing a fatal in NodeAccessControlHandler::checkFieldAccess() during publish.
The fix filters out value-less field-item properties in castRawPhpTypes(), matching the behavior of a freshly loaded item and remaining deterministic regardless of prior instantiation. The config-entity component-tree optimization in toStorableArray() now operates on a clone of the entity so the caller's object is never mutated as a side effect. A canvas_post_update_0023_rehash_auto_save_items resaves every existing auto-save items data, data_hash, and original_hash with the new normalization so conflict detection is not disrupted on sites with pending drafts at the time of update.
As canvas_post_update_0023_rehash_auto_save_items recomputed original_hash for all auto-save items, we no longer need to cover for scenario where 'conflict detection is attempted on auto-save item that might not have original_hash property at all'. This MR removes that logic and associated test coverage.
Testing
On a site with existing auto-save items, run drush updb and verify pending drafts are still present and conflict detection still functions correctly.
AI use disclosure
Portions of this MR - documentation of all changes, minor logic refactoring since the initial commit and the test cases - were produced with AI assistance (GitHub Copilot / Opus 4.8 / Sonnet 4.6). All changes were reviewed and modified by a human, per Drupal.org's policy on AI use when contributing.