Register notify_me_when so admins can govern it

What does this merge request do and why?

notify_me_when schedules the agent to resume itself later, for example when a pipeline finishes. It was in neither built_in_tool_definitions.rb nor PRIVILEGE_GROUP_MAPPING, so no ai_tool_rule could reach it and it did not appear in the tool governance settings at all.

This adds a catalog entry (id 105) and a new agent_internal group for it, with category "Agent", a read action type and a default of Allow. Admins can now see it, it defaults to no prompt, and an ask or deny rule applies to it.

Raised on ai-assist#2906. The group choice was agreed there with @nrosandich.

Why its own group

The first version put it in read_only_gitlab, the only group that defaulted to allow. That was a mislabel, since the tool is not a GitLab read, and it had a real cost: resolve_group demotes a whole group to ask when one tool disagrees, so an ask or deny on notify_me_when emptied the namespace's allow list. Measured on GDK against a namespace with no other rules:

rule on notify_me_when claim allow before claim allow now row pre_approved_agent_privileges now
none 76 76 [2, 7]
ask 0 75 [2, 7]
deny 0 75 [2, 7]

In its own group, a rule reaches this one tool and nothing else.

The resolver change

agent_internal has no AgentPrivileges constant: no workflow privilege grants the tool, and the Duo Workflow Service does not need one. But ResolutionService#execute walked PRIVILEGE_GROUP_TO_CONSTANT, so a group without a constant was skipped entirely. An admin could set deny, the settings page would show deny, and nothing would enforce it.

The loop now walks PRIVILEGE_GROUP_MAPPING. A group without a constant still emits its per-tool denied_tools, ask_tools and pre_approved_tools, and adds nothing to agent_privileges. agent_privileges is unchanged for every existing group; its only consumer assigns or intersects the array.

A spec pins that agent_internal is the only group allowed to lack a constant, so the next one is a deliberate choice.

The other half

For custom agents, registration alone stops the prompt: they run as chat-partial, and DWS pre-approves whatever the claim allows, which now includes this tool by default. For the developer flows, pre-approval is granted by the Duo Workflow Service, and the companion MR adds the tool to _PREAPPROVED_CAPABILITY_TOOLS there: ai-assist!7044 (merged 2026-09-29). That one delivers the silence for the developer flows; this one delivers the visibility and the override. No change is needed on the DWS side for the new group, since only per-tool names reach it.

Conflicts

Rebased onto !257167 (merged) (merged 2026-09-30): the when :ask branch keeps its per-tool pre-approval and gains the if constant guard. The catalog id moved from 104 to 105 because master took 104 while this was open. !256385 (merged) still edits the neighbouring DEFAULT_PREAPPROVED_GROUPS line and the docs matrix row above the new one; whichever merges second rebases.

Tests

  • registry_spec: the tool is rulable, defaults to allow, and reports as read.
  • resolution_service_spec: it is pre-approved by default; an ask or deny on it lands in the claim, removes only this tool, and leaves read_only_gitlab pre-approved; the same example asserts agent_privileges carries no nil, which fails without the if constant guard; and the group-to-constant sync check. The existing "every tool in the default-allow group is set to ask" example now covers every group in DEFAULT_PREAPPROVED_GROUPS.
  • doc/user/ai-governance/tool-governance.md: the default governance matrix gains a Read (agent session) | Always Allow row, since the tool reads neither GitLab resources nor local files.

Mutation-checked: reverting the loop to PRIVILEGE_GROUP_TO_CONSTANT fails four examples.

672 examples pass across the tool-rules lib, service, model and GraphQL specs, plus the Duo workflow services that consume the resolution. The request specs in the same area fail locally on a Vite manifest error that also reproduces on clean master; CI covers them.

How to set up and validate locally

Ai::ToolRules::Registry.all_tool_names.include?('notify_me_when')            # => true
Ai::ToolRules::Registry.default_permission_for(tool_name: 'notify_me_when')  # => "allow"
Ai::ToolRules::Registry.category_for('notify_me_when')                       # => "Agent"

The tool should also appear in the group or project tool governance settings page, under "Agent", set to Always Allow, for a namespace with no rules.

MR acceptance checklist

This change follows the MR acceptance checklist.

Edited by Pratyaksh Golash

Merge request reports

Loading
Loading