Persist the functional verification run's outcome

What does this MR do and why?

Duo's functional verification check is an admin-triggered diagnostic that runs a real Duo Workflow chat session to confirm a self-hosted model deployment works end to end. This MR adds a state-machine hook that records whether each run passed or failed and persists that in the functional_verification_runs table.

Note:

  • During a failure, DWS only surfaces the error to the browser. It never takes another successful step afterward, so nothing new gets saved to Rails, and the error is unrecoverable server-side.
  • Fixing that properly is risky as it involves changing DWS's shared crash-teardown code used by every workflow type (chat, software dev, external agents) adds latency on every failure.
  • Instead, the frontend will handle the real error message live. Rails just stores a generic error message (required since the model validates message presence on failure.
  • Issue to persist the error message will be handled in next iteration: [BE] Persist the functional verification run fa... (#629239)

Screenshots

Passed Failed
Screenshot_2026-09-16_at_12.47.33_AM Screenshot_2026-09-16_at_12.47.13_AM

References

Closes #627468 (closed) Parent: #602572 (closed)

How to set up and validate locally

  1. Enable the duo_agentic_chat_verification_check feature flag and configure a self-hosted model for agentic chat.
  2. Pull the FE counterpart branch from this draft MR: Drive agentic chat verification run over WebSocket (!255676 - merged) and follow steps to trigger a verification check run.
  3. In Rails console, run Ai::DuoAgentPlatform::FunctionalVerificationRun.current_for(:agentic_chat) and expect the following results:
# failed

<Ai::DuoAgentPlatform::FunctionalVerificationRun:0x0000000149af5768
 id: 1,
 workflow_id: 357,
 created_at: "2026-09-10 11:50:05.134846000 +0000",
 updated_at: "2026-09-15 23:46:46.547403000 +0000",
 check_type: "agentic_chat",
 status: "failed",
 message: [FILTERED]>
Ai::DuoAgentPlatform::FunctionalVerificationRun.current_for(:agentic_chat).message # => "An error occurred during the verification check run."

# passed
<Ai::DuoAgentPlatform::FunctionalVerificationRun:0x0000000149af5768
 id: 1,
 workflow_id: 357,
 created_at: "2026-09-10 11:50:05.134846000 +0000",
 updated_at: "2026-09-15 23:46:46.547403000 +0000",
 check_type: "agentic_chat",
 status: "passed",
 message: nil

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist.

Edited by Cindy Halim

Merge request reports

Loading
Loading