Set a work item status when a triggered session finishes
What does this MR do and why?
This MR adds two settings to an AI flow trigger. They let a trigger move a work item to the next status when its flow session finishes.
-
status_on_finish: the name of a work item status, up to 255 characters. A blank value is stored asnil. -
ready_merge_requests_on_finish: a boolean,falseby default. Whentrue, GitLab takes the Draft merge requests that the session created out of Draft. -
Both settings are valid only on a trigger that uses the
work_itemevent type, withStatus changedas its only work item action and at least one status. The model rejects them on other triggers. -
The settings move a work item from the status that the trigger filters on to the next status.
-
A session does not record which work item action started it. So the work item filter must have one top-level rule
action in ["status_changed"], and it must match all its rules. -
The work item filter must also have one top-level
status.namerule with theinoperator and at least one status name. When the session finishes, the worker checks that the work item still has one of these statuses. -
The trigger form reads the action and status rules in the same way.
-
The follow-up UI merge request shows the fields in the trigger form under the same conditions:
Status changedis the only work item action, and at least one status is selected.
Both settings are GraphQL-only (statusOnFinish, readyMergeRequestsOnFinish) and marked experiment in milestone 19.6. The UI does not show them yet.
A feature flag, ai_flow_trigger_status_on_finish, controls the behavior. The flag is wip and is not enabled for customers.
Customers cannot use the feature until a follow-up merge request adds the fields to the trigger form.
This MR is the first step of a multi-MR feature:
- This MR: the backend, behind the
wipflag. - A follow-up MR: the UI fields in the trigger form, behind the same flag, and the user documentation.
- Rollout, after the UI exists and after the dependencies in the References section are met.
The issue has the details of the plan: #633112
The new Sidekiq worker Ai::FlowTriggers::ApplyOnFinishSettingsWorker applies the settings. It runs when a session that a work item event started reaches finished.
Details: behavior, identity, and limits
The worker subscribes to Ai::DuoWorkflows::WorkflowFinishedCloudEvent. The event payload does not change. The subscription filter enqueues the worker only for a session that a trigger started, and only when the feature flag is enabled for its top-level group. So a Sidekiq node that does not know the worker gets no job before the flag is enabled.
The worker changes nothing in these cases:
- The session is stopped, failed, or waits for input.
- A mention or an assignment started the session.
- The flag
ai_flow_trigger_chainingis disabled for the top-level group. - A human event did not start the chain. The worker finds the first session of the chain with the walk that the chain limits use. A human user and a
mention,assign, orwork_itemevent must have started that session. A system event, such as a merge conflict, starts a session as a user who did not act. - The trigger is turned off.
- The session does not run on a work item.
- A work item event started the session, and the work item no longer matches the work item filter of the trigger. The worker evaluates the filter with
Gitlab::FilterEvaluator, so all operators andmatchtypes apply. It uses theStatus changedaction and the current status of the work item. - The service account of the session does not enforce composite identity.
- The service account and the human cannot update the merge request or the work item. The worker checks this with
Abilitybefore each write.
With ready_merge_requests_on_finish, the worker first takes the Draft merge requests out of Draft. It finds them through the created merge request links of the session. With automatic Duo Code Review on, GitLab then adds Duo Code Review as a reviewer.
The worker does not take a merge request out of Draft when auto-merge is set on it. See the identity paragraph below.
Then, with status_on_finish, the worker sets the work item status by name.
If a Draft merge request that the session created stays a Draft, the worker does not set the status. The next stage expects a merge request that is ready for review.
The worker writes as the composite identity of the session, with the session as the workflow of the request. The composite identity is the service account of the flow, scoped to the human who started the chain.
So the status change is an event that a flow caused. With ai_flow_trigger_chaining, the finished session becomes the parent of the next session, inside the chain depth, breadth, and size limits.
The worker requires this flag. With only allow_flow_originated_cloud_event_triggers, the next session starts a new chain, which has no depth limit.
The worker links the identity only for the two writes. After the writes, the worker restores the request store, which also drops the permission results that it cached under that identity. Sidekiq jobs that the two writes queue inherit the identity, as for any write that a session makes. The auto-merge job that a ready merge request starts is one of them, and it can merge as the service account. So the worker leaves a Draft merge request with auto-merge as a Draft, and the user who set auto-merge marks it as ready.
Each log line of the worker has the session, the trigger, the service account, and the user. The flow_trigger_created and flow_trigger_updated audit events record the old and new values of the on-finish settings.
Limits:
- A session can finish but not do the work. For example, Duo Developer can decide that no code change is needed and open no merge request. The status still moves.
- A session that runs on a merge request changes nothing.
- If
status_on_finishis one of the statuses in the trigger filter, the status change can start the same trigger again. - A chain that a session without a trigger started gets no on-finish writes. For example, a session that a user starts through the API. A status change by a human starts a new chain.
- The settings apply only to work items in a project. A trigger does not start for an epic.
- A Draft merge request with auto-merge stays a Draft, so the status does not move.
Evidence: a GDK measurement on 2026-10-09, with a local implementation. The issue lists the observations.
Commits
The MR has these changes:
- A regular migration that adds both columns to
ai_flow_triggers. It adds the 255-character limit onstatus_on_finishasNOT VALID. - A post-deployment migration,
20261012093000, that validates the limit. Thegoalscolumn of the same table uses the same pattern. - The model, GraphQL, subscription, worker, Sidekiq queue files, specs, and the regenerated GraphQL reference. The worker uses the default retry count. The CI job for the GraphQL reference requires the regenerated file.
- The settings apply only to a trigger with
Status changedas its only work item action and at least one status. - The worker uses the composite identity only for the two writes, and holds the status while a merge request of the session stays a Draft.
- The worker writes only with
ai_flow_trigger_chaining, and only for a chain that a human event started. - The worker logs both identities, and the audit events record the on-finish settings.
- The worker leaves a Draft merge request with auto-merge as a Draft.
- The worker uses the
dap_triggersfeature category, and the GraphQL descriptions state the project scope.
This MR has no user documentation. The documentation moves to the UI merge request, because it describes the form.
Review needs
- Database review: the migrations add two columns to
ai_flow_triggers, which is a small table, and validate a limit.- The regular migration passes on all databases.
- The post-deployment migration has one warning on the main database.
ALTER TABLE ai_flow_triggers VALIDATE CONSTRAINT check_bdfe4dd722took 1282 ms, against the 100 ms query guideline. - This validation runs after deployment.
VALIDATE CONSTRAINTtakes aSHARE UPDATE EXCLUSIVElock, which does not block reads or writes. - Results: https://gitlab.com/gitlab-org/gitlab/-/jobs/17107006871
- Application Security review: the worker links a composite identity with the
:authenticationcontext in a Sidekiq job. This is a deliberate choice, so the next trigger sees an event that a flow caused. A write as the plain human would remove the chain bounds. The Application Security review found no blockers. This MR fixes F1, F2, and F4, and the auto-merge case of F3.
References
- Related to #633112. The follow-up UI merge request closes the issue.
- !261053 (merged) lets a
work_itemstatus trigger start Duo Developer. The Duo Developer stage needs it. It merged on 2026-10-12. - The on-finish writes require https://gitlab.com/gitlab-org/gitlab/-/work_items/630476 (
ai_flow_trigger_chaining). - Rollout starts only after the UI merge request is merged and
ai_flow_trigger_chainingis rolled out.
Screenshots or screen recordings
This MR has no UI change. The settings are GraphQL-only.
| Before | After |
|---|---|
| Not applicable | Not applicable |
How to set up and validate locally
- In the Rails console, enable the feature flags for a group or project:
group = Group.find_by_full_path('<group path>') Feature.enable(:ai_flow_trigger_status_on_finish, group) Feature.enable(:ai_flow_trigger_chaining, group) - Create a trigger on a
work_itemevent withStatus changedas the only action, and a status filter, for examplePlanning. - Set
statusOnFinishon the trigger through GraphQL:mutation { aiFlowTriggerUpdate(input: { id: "gid://gitlab/Ai::FlowTrigger/<id>" statusOnFinish: "Ready for development" readyMergeRequestsOnFinish: false }) { aiFlowTrigger { statusOnFinish readyMergeRequestsOnFinish } errors } } - Move a work item to the trigger status.
- Wait for the flow session to finish.
- Check that the work item status changes to
Ready for development. The status change shows the service account of the flow as the actor. - Optional: set
readyMergeRequestsOnFinish: trueon a Duo Developer trigger. Check that the Draft merge request of the session leaves Draft.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.