Keep Duo mention started note as durable record
What does this MR do and why?
Implements the UX improvement requested in #602991: when a Duo mention workflow completes, we remove the transient "started" (thinking) system note and append a "View session" link to the result message, so the session stays referenced close to the outcome instead of leaving a leftover system note in the thread.
Before: The "started … session N and will let you know when it's finished" note stayed in the thread after completion (or behaved inconsistently across surfaces), and on the bot path it could disappear/reorder unexpectedly on live update.
After: While the flow runs, the started note shows an animated loader. Once the result lands, the started (thinking) note is destroyed and the reply note is posted with a [View session](url) link appended at the bottom. This works for both the @GitLabDuo bot path and the Duo Developer service-account path on MRs.
This direction was agreed in the review threads (see discussion): show the thinking message, remove it once the result lands, and append the session details to the result message (starting small with a simple "View session" link, taking design inspiration from the Code Review path as a follow-up).
Changes
Backend
duo_mention_startedbuildsSystemNoteMetadata(action:duo_mention_started) andNotes::NoteDuoMetadata(workflow_id,namespace_id) on the created note, so the workflow link is queryable without parsing the note body.deliver_result/deliver_errorload the started note once (load_started_note), reuse it for both the workflow lookup and destruction (no duplicate query), then destroy it and post the reply.destroy_started_noterescuesActiveRecord::RecordNotDestroyedand tracks the exception so a destroy failure never blocks the reply.deliver_resultappends a[View session](url)link to the reply viaappend_session_link. A blank result message still posts the session link rather than being swallowed.- Session wording drops the word "mention" → "session N".
NoteEntityexposesduo_session_status(the workflow'sstatus_name, not the raw enum), gated on theduo_mention_startedaction, used by the frontend to route rendering and drive the spinner.
Frontend
- Routing of the styled Duo system note is centralised in a single
shouldRenderAsDuoSystemNote(note)helper (~/notes/utils.js), used by bothdiscussion_notes.vueandnotes_app.vue. It routes on the presence ofduo_session_status(covers both the bot and service-account mention notes) and keeps theduo_code_review_botauthor check for the separate Duo Code Review progress note (which has noduo_session_status). - Removal of the started (thinking) note on reply is centralised in a single
findStartedNoteForReply(notes, discussions)helper (~/notes/utils.js), called from bothstores/actions.jsandlegacy_notes/actions.js(kept symmetric, infetchUpdatedNotes). The helper only removes a started note when an incoming reply note shares a discussion that actually contains a started note (duo_session_statuspresent), so ordinary comments no longer trigger removal. duo_code_review_system_note.vue: the loader is shown and animated only while the session is in progress (created/running) and hidden once terminal (finished/failed/stopped) or waiting; absent status falls back to animated for notes created before this field existed.
Out of scope / follow-ups
- Issues (work items) use a separate GraphQL notes stack and do not render the styled card/spinner. The backend durability (persist + destroy-on-completion) works there, but the visual unification is a follow-up.
- A richer styled "View session" treatment (matching the Code Review design) instead of the simple markdown link.
- The shared
DuoCodeReviewSystemNoteavatar styling differs slightly from a normal note avatar (pre-existing). - MR-vs-issue system-note unification and any public API exposure.
References
- #602991
- gitlab-org#22067
- Main work item: #601705
How to set up and validate locally
Prereqs: a DAP-onboarded project with the mention foundational flow(s) enabled and a :mention service-account trigger, and the Duo Workflow executor running in GDK.
# Duo Developer @mention path
Feature.enable(:ai_use_messaging_adapter_for_mentions)- Duo Developer
@mention(MR thread): comment@<duo-developer-service-account> …on an MR.- A started note appears — "started session N and will let you know when it's finished" — with an animated loader.
- When the flow completes, the started (thinking) note is removed and the reply note is posted with a
[View session](url)link appended at the bottom — without reloading.
@GitLabDuoMR mention (requiresduo_foundational_flows_enabled+ the code-review catalog item enabled on the project): comment@GitLabDuo …on an MR.- Same started → removed-on-completion behavior, and the started note no longer disappears or jumps position when unrelated comments arrive on live update.
- Failure path: trigger a flow error (e.g. by cancelling the session) → the started note is removed and an error reply is posted.
- Try the same on an issue (the UI will look a bit different there but this is parked for a follow-up).
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.