Canvas AI: canvas_ai_post_update_0003 strips the orchestrator agent UUID via setData()
## Overview `canvas_ai_post_update_0003_reimport_orchestrator_agent()` in `modules/canvas_ai/canvas_ai.post_update.php` reimports the orchestrator agent to pick up a changed system prompt (follow-up to [#3582390](https://www.drupal.org/project/canvas/issues/3582390)). It reads `config/install/ai_agents.ai_agent.canvas_ai_orchestrator.yml` and calls `->setData($data)->save(TRUE)`. The install file has no top-level `uuid` key. `setData()` replaces the entire config record, so the existing `uuid` is dropped from the active `ai_agents.ai_agent.canvas_ai_orchestrator` config. The hook shipped in **1.5.0** and **1.5.1**, so it has already run on updated sites. After the update, `drush cex` records the `uuid` line as deleted, producing config drift. Sibling hooks `0002`, `0004`, and `0005` use `->set()` and keep the uuid; only `0003` uses `setData()`. ### Steps to reproduce 1. Start from an existing site (1.4.x or earlier) that has the orchestrator agent installed. 2. Update to 1.5.0 or 1.5.1 and run database updates. 3. Run `drush cex --diff`. 4. The `uuid` line is removed from `ai_agents.ai_agent.canvas_ai_orchestrator.yml`. ## Proposed resolution **PHP — `modules/canvas_ai/canvas_ai.post_update.php`** 1. Preserve the existing uuid in `canvas_ai_post_update_0003_reimport_orchestrator_agent()` before calling `setData()`: ```php $config = \Drupal::configFactory()->getEditable('ai_agents.ai_agent.canvas_ai_orchestrator'); if (!$config->isNew()) { $data['uuid'] = $config->get('uuid'); } $config->setData($data)->save(TRUE); ``` 2. Add a repair post_update that restores a uuid on sites that already ran `0003`. Loop the module's installed agent configs so it covers any affected agent: ```php /** * Restore UUIDs stripped from Canvas AI agent config by post_update 0003. */ function canvas_ai_post_update_0006_restore_agent_uuids(): void { $uuid = \Drupal::service('uuid'); $module_path = \Drupal::service('extension.list.module')->getPath('canvas_ai'); $source = new FileStorage($module_path . '/config/install'); foreach ($source->listAll('ai_agents.ai_agent.') as $name) { $config = \Drupal::configFactory()->getEditable($name); if (!$config->isNew() && !$config->get('uuid')) { $config->set('uuid', $uuid->generate())->save(TRUE); } } } ``` UUIDs are assigned per site at install time, so there is no canonical value to restore. A fresh uuid stops the export drift. **Tests** - Add a kernel test that installs the orchestrator agent, runs `0003`, and asserts the active config keeps its uuid. - Cover `0006`: clear the uuid, run the hook, assert a uuid exists. ## User interface changes None. --- 🤖 AI assistance was used to diagnose this issue and draft the proposed resolution, per the [Drupal.org policy on AI contributions](https://www.drupal.org/docs/develop/issues/issue-procedures-and-etiquette/policy-on-the-use-of-ai-when-contributing-to-drupal).
issue