Draft: Add Duo workplan: decision log, confidence scoring, status flow

Draft — for hands-on trial, not review-ready. See "Known gaps" before reviewing; several pipeline gates are knowingly red.

Companion: gitlab-org/modelops/applied-ml/code-suggestions/ai-assist!6398 (closed) (the flow definitions). Neither half works alone.

What this is

The planning half of a "software factory" for GitLab Duo. An agent researches a work item against the real codebase, settles what it can on its own, records every decision it makes, and publishes an implementation plan that a separate critic agent scores before implementation starts. A human steers by owning decisions, not by writing the plan.

What's in it

WorkItems::Decision — an append-only decision log. Rows are never edited, only superseded, so the record of why a plan looks the way it does survives being changed. source records who decided (the agent on its own, a human answering a gate, a resolved thread); kind separates plain choices from acceptance criteria. The two are orthogonal on purpose.

This turned out to be the steer channel rather than just an audit trail: gate answers round-trip through GitLab and come back to the agent via get_work_item, which was discovered rather than designed.

WorkItems::AgentPlan confidence. Six scored dimensions plus a content digest and scored_at, so a plan whose content or decisions moved after scoring reports as stale rather than being silently trusted.

An add_workitem_decision MCP tool. The flow records its own decisions through the same API a human would use. The target work item is pinned from the session rather than chosen by the model — an early live run filed 5 of 8 decisions against an unrelated issue it had been reading as prior art.

Configurable work item status transitions. Flow lifecycle events map to work item statuses via .gitlab/duo/factory.yml in the target project, so teams define their own factory stages instead of inheriting hardcoded ones. No file means a built-in mapping; a malformed file is refused rather than silently defaulted, because a team that wrote a file wanted their rules, not ours.

Command Center. A cross-project view of the agent sessions that need a human, with a topbar pill count.

Async flow starts — no chat session, no Duo Chat window.

Trying it out

  1. bundle exec rails db:migrate — five migrations; db/structure.sql is deliberately not in this MR (see below).
  2. Enable feature flags workplan_flow and workplan_decision_log (both default off).
  3. Enable the workplan/v1 foundational flow for your project.
  4. For MCP decision recording: mcp_client on, plus duo_workflow_mcp_enabled on the group. If these are off the flow still runs and simply records no decisions, silently — worth checking before concluding it's broken.
  5. Optionally add .gitlab/duo/factory.yml to map flow events onto your statuses.

Note the flow runs as a CI job tagged gitlab--duo, not in your browser — so runner concurrency caps how many plans can be built at once.

Known gaps — please read

Pushed with --no-verify. These gates are red and I know it:

  • db/structure.sql omitted. This working tree carries ~1,200 lines of unrelated schema drift; only ~74 lines belong to these migrations. Shipping it would have buried the real change. Danger will flag "New migrations added but db/structure.sql wasn't updated" — correct, and deliberate.
  • permissions_docs — four new GraphQL types need authorize_granular_token plus per-boundary tests: WorkItemAgentPlanConfidence, WorkItemAgentPlanConfidenceDimension, WorkItemWidgetDecisionLog, WorkItemDecision. Real work, not yet done.
  • graphql_introspection_check and openapi_docs — generated artefacts not regenerated.
  • unused-methods-linter — flags confidence_band, decisions_stale?, superseded?, active_decisions. At least decisions_stale? may be genuinely dead: the GraphQL resolver re-implements the same predicate with a BatchLoader rather than calling the model method. Worth resolving properly rather than adding to the exclusion list.
  • validate-fast-spec-helper — not yet investigated.
  • Danger: "definitely too big (36k lines)". Fair. This is an exploratory branch for people to try, not a merge candidate; it wants splitting before it becomes one.

Rubocop, eslint, prettier, jsonlint, haml-lint, gettext, stylelint and commit-message linting all pass.

Merge request reports

Loading
Loading