Auto-update default prompt entities on module updates, but only if the site has not customized them
>>> [!note] Migrated issue
<!-- Drupal.org comment -->
<!-- Migrated from issue #3582350. -->
Reported by: [marcus_johansson](https://www.drupal.org/user/385947)
Related to !1447
>>>
<p>[Tracker]<br>
<strong>Update Summary: </strong>[One-line status update for stakeholders]<br>
<strong>Short Description: </strong>Auto-update default prompt entities on module updates, but only if the site has not customized them<br>
<strong>Check-in Date: </strong>MM/DD/YYYY<br>
[/Tracker]</p>
<h3 id="summary-problem-motivation">Problem/Motivation</h3>
<p>When the AI module or its submodules ship updated default prompts (e.g. improved wording, new variables, bug fixes in prompt text), existing installations do not receive these updates. The prompt entities are config entities that are only written on initial install. After that, any improvements to default prompts require manual intervention by site administrators or custom update hooks per change.</p>
<p>However, blindly overwriting prompt entities on update would destroy customizations that site editors have made. Many sites intentionally tailor their prompts - for example adjusting tone, adding domain-specific instructions, or translating them. These customizations must be preserved.</p>
<p>What is needed is a hash-based mechanism that tracks whether a prompt entity still matches its original installed state. On module update, the system should compare the current prompt against the hash of the previously shipped default. If the prompt is unmodified (hash matches), it is safe to update to the new default. If the prompt was customized by the site (hash differs), the update is skipped and the customization is preserved.</p>
<p>Drupal Commerce already implements this pattern in its <a href="https://git.drupalcode.org/project/commerce/-/blob/3.x/src/Config/ConfigUpdater.php?ref_type=heads">ConfigUpdater</a> service, which uses <code>_core.default_config_hash</code> and <code>Crypt::hashBase64(serialize($config))</code> to detect user modifications before reverting config. The AI module should adopt a similar approach for prompt entities.</p>
<p>The discussion came from <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-14"><a href="https://www.drupal.org/project/ai/issues/3576689" title="Status: Reviewed & tested by the community">#3576689: Default prompt flagged with content violation</a></span> and <a href="https://drupal.slack.com/archives/C0803LX4536/p1774870270095329">https://drupal.slack.com/archives/C0803LX4536/p1774870270095329</a></p>
<h3 id="summary-proposed-resolution">Proposed resolution</h3>
<ul>
<li>Create a <code>PromptConfigUpdater</code> service (or extend <code>AiPromptManager</code>) that can compare the current prompt entity state against a stored hash of the previously shipped default.</li>
<li>On install of a prompt entity, store a hash of the default prompt content (using <code>Crypt::hashBase64</code>) alongside the entity - either in a dedicated field on the entity or via <code>_core.default_config_hash</code>.</li>
<li>Provide a method like <code>isModified(AiPromptInterface $prompt): bool</code> that compares the stored hash against the current prompt content to determine if the site has customized it.</li>
<li>Provide an update method that accepts new default prompt content and only applies the update if <code>isModified()</code> returns <code>FALSE</code>.</li>
<li>When an update is skipped because the prompt was modified, log a notice so administrators are aware a new default is available.</li>
<li>Submodules (ai_translate, ai_content_suggestions, etc.) should use this service in their <code>post_update</code> hooks when shipping prompt improvements.</li>
<li>Use the Commerce <a href="https://git.drupalcode.org/project/commerce/-/blob/3.x/src/Config/ConfigUpdater.php?ref_type=heads">ConfigUpdater</a> as architectural reference for the hash comparison pattern.</li>
<li>Add tests covering both scenarios: prompt updated when unmodified, prompt preserved when customized.</li>
</ul>
<h3 id="summary-ai-usage">AI usage (if applicable)</h3>
<p>[x] AI Assisted Issue<br>
This issue was generated with AI assistance, but was reviewed and refined by the creator.</p>
<p>[ ] AI Assisted Code<br>
This code was mainly generated by a human, with AI autocompleting or parts AI generated, but under full human supervision.</p>
<p>[ ] AI Generated Code<br>
This code was mainly generated by an AI with human guidance, and reviewed, tested, and refined by a human.</p>
<p>[ ] Vibe Coded<br>
This code was generated by an AI and has only been functionally tested.</p>
<p>- <strong>This issue was created with the help of AI</strong></p>
issue