Load Duo readiness row state asynchronously
What does this MR do and why?
The Duo Agent Platform readiness card sits behind the duo_agent_readiness_settings feature flag. Before this change, every page view ran a runner scan and counted connected MCP servers. This work slowed the settings page for every viewer.
This MR moves both checks off the page load. The CI/CD runner row and the MCP servers row now load after the page renders. They get their state through GraphQL. Each row shows a loading state first, then its result. If a check fails, only that row shows an error and a retry option. The rest of the page still works.
The check for the agent configuration file still runs while the page loads. This is deliberate. The result is cached for five minutes, so the check usually costs a few milliseconds. The checks the parent issue keeps at page load cost about the same. When the file is missing, the page also looks for an open merge request that adds it. This adds one database query, limited to the project's open merge requests. The parent issue (#607910 (closed)) asked to defer every check. This MR defers the two heavy checks and keeps this cheap one at page load.
The agent configuration file row now also knows about a run that is already active. At page load, the row links the running session instead of offering Generate. If the user clicks Generate while a run is active, the server returns the running session, and the row links it instead of showing an error.
This MR adds one new GraphQL field on the Project type: duoMcpServersCount. It is an experiment field, added in GitLab 19.3. The runner row reuses two existing fields.
The issue warned that the MCP servers row and the page it links to used different access checks. A user could see the link but land on a missing page. In this MR, the row, the new GraphQL field, and the destination page all rely on the same permission. A user who can see the row can always open the page. No new shared check was needed, because one permission already covers both places.
The page also skips extra work for rows a viewer can never see. This happens when the flag is off, when Amazon Q is active, or when the viewer lacks permission. If authorization redacts an answer, this MR treats it as a failed check. It does not treat it as "no runner found".
This MR is one half of a larger change that was split in two. This MR handles the async row loading. The card UI and progress header follow in !252535 (merged), stacked on this branch.
How to test locally
Automated tests: the frontend suite for the settings area passes (798 tests). Backend specs cover the helper, the readiness logic, and the new GraphQL field. Rubocop, prettier, eslint, and the translation file checks all pass. The change was also checked in a browser on GDK.
Manual steps:
- Enable the
duo_agent_readiness_settingsfeature flag. - Open a project. Go to Settings > General.
- Expand the GitLab Duo section.
- Watch the runner row and the MCP servers row. Each shows a loading state, then a result.
- Confirm the rest of the page loads without waiting for these two rows.
- Click Generate on the agent configuration file row. Reload the page. The row links the running session.
References
- Closes #607910 (closed).
- Part of epic gitlab-org#22591.
- The card UI half of the split: !252535 (merged).