Moodle 5.3 marks `external_generate_token()` as a final deprecation
(`#[deprecated('\core_external\util::generate_token', since: '4.4',
final: true)]` in public/lib/externallib.php), and
`core\deprecation::emit_deprecation_notice()` throws a coding_exception
for every final deprecation, whatever the debug level. The MCP
provisioning script called it whenever no permanent token existed yet,
so every fresh install of the variant that enables MCP failed at
"Enable web services and mint the MCP bearer" (main run 39494396920,
Moodle#1: `Error code: codingerror` from deprecation.php:273 via
externallib.php:30).
The variant had not run in CI since the Moodle 5.3 bump, which is why
this surfaced only now.
Mint the token with `\core_external\util::generate_token()`, which
takes the service record instead of its id, and create the service
account with `\core\user::create_user()` in place of
`user_create_user()`, deprecated since 5.3 (MDL-82650). Neither needs
externallib.php or user/lib.php any more.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
provision_ai_gateway.php and provision_mcp.php shared a prefix inside one
directory, which test_prefix_grouped_files rejects. Both move into
files/php/provision/ as ai_gateway.php and mcp.php, the layout
web-app-n8n already uses for its Python provisioning scripts.
The two lookups that feed the scripts to the container follow, and the
unit test moves to its mirrored path as provision/AiGatewayTest.php.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Moodle 5 keeps AI provider settings in provider instances, not in the
plugin configuration. The deploy kept writing aiprovider_openai/* through
cfg.php and read the same value back, so its own check stayed green while
no provider existed. The gateway spec then found no settings page and
web-app-moodle#2 failed in run 37646050826.
The deploy now pipes files/php/provision_ai_gateway.php into the
container. It finds the instance by class and name or creates it through
core_ai\manager, points the three text actions at the chat endpoint,
switches image generation off, stores the virtual key and prints what
Moodle stored. The task asserts on that output. An instance an
administrator added is left alone.
The spec finds the instance by MOODLE_AI_PROVIDER_NAME on the providers
page and reads the endpoint from its generate_text action page.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The merged branch moved every role-local script out of files/ into a folder
named for its language (files/python/, files/php/, files/shell/), but the
moves lost their staging and never landed. HEAD still carried the old paths
while the worktree had the new ones.
Move the 24 remaining scripts and update the six places that resolve them:
the mcp-adapter instance/isolation/probe tasks, the litellm key task, the
adapter README and the endpoint-path lint. Every changed line in those
files is a path.
Also drop roles/sys-svc-compose/files/swarm/stack_ready.sh, a stale
duplicate of the copy already tracked under files/shell/swarm/.
The added comments are the branch's own `nocheck: mirrored-unit-test`
directives, which state why a script whose measurement only exists inside
its container cannot have a mirrored unit test.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>